我的回答假设您只希望 auser
成为roomie
at one dwelling
。如果您希望 auser
超过roomie
一个dwelling
,我认为@ari 的答案很好,尽管我可能会选择has_and_belongs_to_many
而不是has_many :through
.
现在我的回答是:
我会设置它,以便住宅belongs_to
拥有所有者和has_many
室友(可能包括所有者,但不一定)。
您可以将User
模型用于owners
和roomies
。您不需要任何额外的表或模型,您只需要使用:class_name
and: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
代码导致了一些问题。您需要诊断原因,然后确定您的应用程序在这种情况下应该做什么。有几种方法可以处理这个问题,至少包括以下
- 将所有内容放在事务块中,并使用
current_use.save!
而不是,current_user.save
以便引发异常并且既不保存用户也不保存住所。
- 保存住所,但通知用户他不是室友(如上)
- 与其保存 current_user,不如使用
update_column
(避免回调、验证等)。
我相信您当前遇到的问题与原始问题基本无关。如果您需要进一步的帮助,最好将其作为一个单独的问题分开。