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

时间:2012-08-02 14:11:31

标签: ruby-on-rails associations

我正在尝试在两个现有模型UserDwelling之间创建特殊关系。 Dwelling在创建时只有一个所有者(Dwelling belongs_to :userUser has_one :dwelling)。但是其他用户可以作为Dwelling添加到此Roomies(现在没有为此创建模型,Roomie是概念关系。)

我认为我不需要单独的模型,而是需要与现有模型建立特殊关系,但我可能错了。我认为需要使用user_id表中的Users进行引用。我不确定从哪里开始这个。感谢您的帮助!

例如:

Dwelling1 
  user_id: 1 
  roomies: [1, 2, 3, 4]

其中1,2,3,4是user_ids。

更新模型

Dwelling Model

# dwelling.rb
class Dwelling < ActiveRecord::Base
    attr_accessible :street_address, :city, :state, :zip, :nickname

    belongs_to :owner, :class_name => "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 < ActiveRecord::Base
  attr_accessible :email, :first_name, :last_name, :password, :password_confirmation, :zip
  has_secure_password

  before_save { |user| user.email = email.downcase }
  before_save :create_remember_token

  belongs_to :dwelling
  has_many :properties, :class_name => "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
...

3 个答案:

答案 0 :(得分:2)

我的回答假设您只希望一个user roomiedwelling。如果您希望user成为多个roomie的{​​{1}},我认为@ ari的答案很好,但我可能会选择dwelling而不是{{1} }}

现在回答我的问题:

我会设置它以便住所has_and_belongs_to_many所有者和has_many :through房间(可能包括所有者,但不一定)。

您可以将belongs_to模型用于has_manyUser。您不需要任何其他表格或模型,只需使用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。您的代码将等同于以下内容:

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)

当住宅成功保存时,当前用户将是所有者(数据库中的: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回调。在许多方面,这将是一种更简洁,更简单的方法。但是,在after_create无法保存的情况下捕捉案例可能比上述方法更加丑陋,具体取决于您希望如何处理它。

我认为底线是Dwelling代码导致了一些问题。您需要诊断原因,然后确定应用程序在这种情况下应该执行的操作。有几种方法可以解决这个问题,至少包括以下内容

  1. 将所有内容放入事务块中,并使用current_user代替current_user.save,以便引发异常,并且不会保存用户或住所。
  2. 保存住宅,但告知用户他不是房间(如上所述)
  3. 使用current_use.save!(避免回调,验证等),而不是保存current_user。
  4. 我相信您遇到的当前问题与原始问题基本无关。如果您需要进一步的帮助,最好将其作为一个单独的问题予以解决。

答案 1 :(得分:1)

您有两种可能的选择。 根据您的计划,住宅可能更清楚,而不是拥有一栋住宅的业主。那么住宅也可以有用户。您可以向User添加一个名为dwelling_id的列,然后您可以为has_many用户提供住所。

另一种选择是使用"has_many through" association。这意味着你需要创建一个跟踪这种关联的新模型,比如“Relationship.rb”,它同时属于User和Dwelling(并且两者都有列)。然后你就可以编写这样的代码:

//in Dwelling.rb
has_many :roomies, through: :relationships, source: :user

//in User.rb
has_many :dwellings, through: :relationships

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

答案 2 :(得分:1)

您可以通过将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

然后,您可以使用以下内容设置房间ID:

roomie_ids = [1, 2, 3, 4]  
@dwelling.roomies = {:ids => roomie_ids}
@dwelling.save!

取自{em>保存数组,哈希以及this 的文本列部分中的其他不可映射对象