在Rails中,如何创建用户组作为另一个关联,例如“成员”?

我试图在两个现有模型UserDwelling之间创建一个特殊的关系。 Dwelling在创建时只有一个所有者( Dwelling belongs_to :userUser 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模型用于ownersroomies 。 您不需要任何其他表或模型,只需使用: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代码导致一些问题。 您需要诊断原因,然后确定应用程序在这种情况下应该执行的操作。 有几种方法可以解决这个问题,至少包括以下几种方法

  1. 将所有内容放在事务块中,并使用current_use.save! 而不是current_user.save以便引发exception,并且既不保存用户也不保留住所。
  2. 保存住宅,但告知用户他不是房间(如上)
  3. 而不是保存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 

这样,用户也可以加入多个住宅。