3

我正在尝试在两个现有模型UserDwelling. ADwelling在创建时只有一个所有者 ( Dwelling belongs_to :user, User has_one :dwelling)。但是可以将其他用户添加到其中DwellingRoomies现在没有为此创建模型,Roomie是概念关系)。

我认为我不需要单独的模型,而是需要与现有模型建立特殊关系,但我可能是错的。我认为需要user_idUsers表格中进行参考。我不确定从哪里开始。感谢您的任何帮助!

例如:

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
...
4

3 回答 3

2

我的回答假设您只希望 auser成为roomieat one dwelling。如果您希望 auser超过roomie一个dwelling,我认为@ari 的答案很好,尽管我可能会选择has_and_belongs_to_many而不是has_many :through.

现在我的回答是:

我会设置它,以便住宅belongs_to拥有所有者和has_many室友(可能包括所有者,但不一定)。

您可以将User模型用于ownersroomies。您不需要任何额外的表或模型,您只需要使用:class_nameand: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)

但是,除非您打开关联,否则此(默认情况下)不会保存房屋,如果它有验证错误: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在许多方面,这将是一种更清洁、更简单的方法。但是,捕获current_user无法保存的情况可能比上述方法更难看,具体取决于您要如何处理它。

我相信底线是current_user.save代码导致了一些问题。您需要诊断原因,然后确定您的应用程序在这种情况下应该做什么。有几种方法可以处理这个问题,至少包括以下

  1. 将所有内容放在事务块中,并使用current_use.save!而不是,current_user.save以便引发异常并且既不保存用户也不保存住所。
  2. 保存住所,但通知用户他不是室友(如上)
  3. 与其保存 current_user,不如使用update_column(避免回调、验证等)。

我相信您当前遇到的问题与原始问题基本无关。如果您需要进一步的帮助,最好将其作为一个单独的问题分开。

于 2012-08-03T02:12:39.313 回答
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!

取自本节的在文本列中保存数组、散列和其他不可映射的对象部分

于 2012-08-02T14:43:21.730 回答
1

你有两个可能的选择。根据您的计划,住宅拥有一个业主可能比业主拥有一个住宅更明确。那么住宅也将能够拥有用户。您可以向 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

这将使用户还可以加入多个住宅。

于 2012-08-02T14:38:35.140 回答