在Rails中,如何创建用户组作为另一个关联,例如“成员”?
我试图在两个现有模型User
和Dwelling
之间创建一个特殊的关系。 Dwelling
在创建时只有一个所有者( Dwelling belongs_to :user
, User has_one :dwelling
)。 但其他用户可以添加到这个Dwelling
作为Roomies
(现在没有为此创建模型, Roomie
是一个概念关系)。
我认为我不需要单独的模型,而是需要与现有模型建立特殊关系,但我可能错了。 我认为需要使用Users
表中的user_id
进行引用。 我不确定从哪里开始这个。 感谢您的帮助!
例如:
Dwelling1 user_id: 1 roomies: [1, 2, 3, 4]
其中1,2,3,4是user_ids。
更新的模型
Dwelling Model
# dwelling.rb class Dwelling "User", :foreign_key => "owner_id" has_many :roomies, :class_name => "User" validates :street_address, presence: true validates :city, presence: true validates :state, presence: true validates :zip, presence: true end
User Model
# user.rb class User "Dwelling", :foreign_key => "owner_id" validates :first_name, presence: true, length: { maximum: 50 } ...
Updated Dwelling Create Action
#dwellings_controller.rb ... def create @dwelling = current_user.properties.build(params[:dwelling]) if @dwelling.save current_user.dwelling = @dwelling if current_user.save flash[:success] = "Woohoo! Your dwelling has been created. Welcome home!" redirect_to current_user else render 'new' end end end ...
我的回答假设您只希望user
成为一个roomie
房间。 如果你想让一个user
成为不止一个dwelling
房间,我认为@ ari的答案是好的,虽然我可能会选择has_and_belongs_to_many
而不是has_many :through
。
现在我的回答:
我会设置它,以便住宅belongs_to
所有者和has_many
房间(可能包括所有者,但不一定)。
您可以将User
模型用于owners
和roomies
。 您不需要任何其他表或模型,只需使用:class_name
和:foreign_key
选项设置正确的关系。
在您的Dwelling
模型中:
# dwelling.rb belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" has_many :roomies, :class_name => "User"
在您的User
模型中:
# user.rb belongs_to :dwelling # This is where the user lives has_many :properties, :class_name => "Dwelling", :foreign_key => "owner_id" # This is the dwellings the user owns
在您的dwellings
表中,您需要owner_id
列来存储所有者的user_id
在您的users
表中,您需要一个dwelling_id
来存储用户居住的dwelling_id
的住宅区。
要在有关控制器的评论中回答您的问题:
如果要将current_user
设置为新住所的所有者,请执行以下操作:
@dwelling = current_user.properties.build(params[:dwelling]) ....
如果要将current_user
设置为新住所的所有者和房间,请执行以下操作:
@dwelling = current_user.properties.build(params[:dwelling] if @dwelling.save current_user.dwelling = @dwelling if current_user.save # flash and redirect go here else # It's not clear why this wouldn't save, but you'll to determine # What to do in such a case. end else ... end
上面最棘手的部分是处理住宅有效并保存的情况,但由于某些不相关的原因,无法保存current_user
。 根据您的应用程序,您可能希望住宅无论如何都要保存,即使您不能将current_user
指定为房间。 或者,您可能希望住宅不被保存 – 如果是这样,您需要使用模型事务,这有点超出了这个问题的范围。
您的控制器代码不起作用,因为保存Dwelling实际上不会更新current_user
记录以存储dwelling_id
。 您的代码将等同于以下内容:
@dwelling = Dwelling.new(params[:dwelling]) current_user.dwelling = @dwelling if @dwelling.save ...
请注意, current_user
永远不会保存,因此current_user.dwelling = @dwelling
行无用。
这似乎是违反直觉的,但最重要的是build_dwelling
实际上并没有像你期望的那样在内存中设置内容。 如果您保存了正在构建的模型而不是您正在构建的模型,则可以获得更直观的结果:
@dwelling = current_user.build_dwelling(params[:dwelling]) if current_user.save # This will save the dwelling (if it is valid)
但是,如果它具有validation错误,则(默认情况下)不会保存住宅,除非您转为:autosave
为关联,这也超出了此问题的范围。 我真的不推荐这种方法。
更新:
这是一个更详细的代码片段:**
# dwellings_controller.rb def create @dwelling = current_user.properties.build(params[:dwelling]) if @dwelling.save # The current user is now the owner, but we also want to try to assign # his as a roomie: current_user.dwelling = @dwelling if current_user.save flash[:notice] = "You have successfully created a dwelling" else # For some reason, current_user couldn't be assigned as a roomie at the # dwelling. This could be for several reasons such as validations on the # user model that prevent the current_user from being saved. flash[:notice] = "You have successfully created a dwelling, but we could not assign you to it as a roomie" end redirect_to current_user else # Dwelling could not be saved, so re-display the creation form: render :new end end
当住宅成功保存时,当前用户将是所有者(数据库中的owner_id
)。 但是,如果current_user
没有保存,则需要确定应用程序应如何响应。 在上面的示例中,我允许保存住宅(即我不回滚其创建),但我通知用户他不能被指定为房间。 发生这种情况时,很可能是应用程序中的其他代码导致了问题。 您可以检查current_user
的错误以查看原因。 或者,您可以使用current_user.save!
而不是current_user.save
临时进行故障排除。
另一种完成所有这些操作的方法是在Dwelling
模型中使用after_create
回调。 在许多方面,这将是一种更简洁,更简单的方法。 但是,当无法保存current_user
时捕获大小写可能比上面的方法更糟糕,具体取决于您希望如何处理它。
我相信底线是current_user.save
代码导致一些问题。 您需要诊断原因,然后确定应用程序在这种情况下应该执行的操作。 有几种方法可以解决这个问题,至少包括以下几种方法
- 将所有内容放在事务块中,并使用
current_use.save!
而不是current_user.save
以便引发exception,并且既不保存用户也不保留住所。 - 保存住宅,但告知用户他不是房间(如上)
- 而不是保存current_user,使用
update_column
(这避免了回调,validation等)。
我相信您遇到的当前问题与原始问题基本无关。 如果您需要进一步的帮助,最好将其作为单独的问题分解。
您可以通过将Roomie ID存储为Dwelling中的列来完成此操作
进行迁移:
class AddRoomiesToDwelling < ActiveRecord::Migration def self.up add_column :dwelling, :roomies, :text end def self.down remove_column :dwelling, :roomies end end
在您的住宅模型中:
class Dwelling < ActiveRecord::Base serialize :roomies end
然后,您可以使用以下内容设置roomie ID:
roomie_ids = [1, 2, 3, 4] @dwelling.roomies = {:ids => roomie_ids} @dwelling.save!
取自本文的文本列部分中的Saving数组,散列和其他不可映射的对象
您有两种可能的选择。 根据您的计划,住宅可能更清楚,而不是拥有一栋住宅的业主。 那么住宅也可以有用户。 您可以向User添加一个名为dwelling_id的列,然后您可以使用has_many用户。
另一种选择是使用“has_many through”关联 。 这意味着你需要创建一个跟踪这种关联的新模型,比如“Relationship.rb”,它既属于User又是Dwelling(并且两者都有列)。 然后你就可以编写这样的代码:
//in Dwelling.rb has_many :roomies, through: :relationships, source: :user //in User.rb has_many :dwellings, through: :relationships
这样,用户也可以加入多个住宅。