【问题标题】:Ruby on Rails: Nested Attributes, belongs_to relationRuby on Rails:嵌套属性,belongs_to 关系
【发布时间】:2009-10-20 11:06:43
【问题描述】:

我有一个具有当前位置字段(城市和国家/地区)的用户实体。为了保存这些信息,我创建了一个名为 Location 的实体,该实体拥有多个用户。

我不完全确定是否应该放入用户模型“has_one”或“belongs_to”,但如果我希望它具有位置的外键,我应该放入“belongs_to”。我还希望能够在编辑用户时编辑用户的当前位置。所以我使用嵌套属性。但是当我编辑用户时,我最终每次都会添加一个新位置,而不会将其与被编辑的用户相关联。你能帮我吗?

我的代码如下:

#User Model
class User < ActiveRecord::Base
  ## Relationships
  belongs_to :current_location, :class_name => 'Location'
  accepts_nested_attributes_for :current_location
end

#Location Model
class Location < ActiveRecord::Base
  #Relationship
  has_many :users
end

# part of the _form_edit.haml
- form_edit.fields_for :current_location do |location_form|
  = location_form.label :location, "Current Location"
  = location_form.text_field :location

#Application Helper
#nested attributes for user and location
def setup_user(user)
  returning(user) do |u|
    u.build_current_location if u.current_location.nil?
  end
end

#in the user controller (added after edit)
def update
    @user = @current_user
    if @user.update_attributes(params[:user])
      flash[:notice] = "Account updated!"
      redirect_to account_url
    else
      render :action => :edit
    end
  end

【问题讨论】:

  • 而在保存数据的控制器中,你有什么?
  • 我有:def update @user = @current_user if @user.update_attributes(params[:user]) flash[:notice] = "帐户更新!" redirect_to account_url else render :action => :edit end end

标签: ruby-on-rails attributes nested belongs-to


【解决方案1】:

正如其他人所指出的那样,您面临的确切问题是您的控制器没有收到应有的位置 ID。在我看来,位置 ID 是通过错误的参数传递的。不幸的是,新记录中不存在位置 ID,因此在表单中是不可能的。

您的问题源于在belongs_to 关系上使用accepts_nested_attributes_for。行为没有明确定义。这似乎是一个记录在案的错误。因此,accepts_nested_attributes_for 应该位于关系的一方或多方。

以下是一些可能的解决方案:

  1. 将accepted_nested_attributes_for 移至Location 模型并以相反的方式构建您的表单。

    -form_for @location do |location_form|
     ...
     =location_form.fields_for @user do |user_form|
       ....
    

    不幸的是,这不允许以合乎逻辑的方式呈现信息。并且使编辑正确的用户变得困难。

  2. 使用连接模型,并建立一个有一个:通过关系。

    老实说,我不确定 accept_nested_attributes_for 与 :through 关系的效果如何,但它肯定会解决链接记录的问题。

  3. 忽略accepted_nested_attributes_for 并以老式方式处理控制器中的关联。

    实际上保留accepts_nested_attributes_for。它提供了一些方便的方法,只是不要让它进入 update_attributes/create 语句。

    def update 
      @user = @current_user 
      completed = false
      location_params = params[:user].delete(:current_location_attributes)
    
      User.transaction do
        @location = Location.find_or_create_by_id(location_params)
        @user.update_attributes(params[:user]) 
        @user.current_location = @location
        @user.save!
        completed = true
      end
      if completed
        flash[:notice] = "Account updated!" redirect_to account_url 
      else 
        render :action => :edit 
      end
    end
    

如果没有创建新位置,Fields for 将自动填充 current_location_attributes 哈希中的 id 字段。但是,find_or_create_by_id 需要哈希中的 :id 条目才能工作。如果 id 不在数据库中,它将使用正确的自动递增 id 创建。如果您要创建新位置,则需要添加它。使用=location_form.hidden_field :id, 0 unless current\_location.new\_record? 最容易将其添加到表单中。

但是,您可能希望减少重复位置创建,并将 Location.find_or_create_by_id 行更改为 Location.find_or_create_by_location。这也将减少因唯一性验证失败而导致的任何错误。

【讨论】:

  • 您好 EmFI tks 为您的回复。我不知道这是一个已知的错误......但我真的试图寻找解决方案并且没有找到任何东西。关于3个选项。 1-确实不是最好的,为此目的.. =/因为我想更改用户的位置。 2- 我不知道该怎么做才能说实话...... 3- 这看起来很不错,我试过了,但它不起作用。 =/ 起初它说没有“删除!”功能,但在删除“!”之后它没有任何错误。它只是没有将位置与用户相关联:s 它只是创建它,仅此而已...... :s 有什么想法吗? ://
  • 是的,我认为 Hash 上存在破坏性删除。同样在我的匆忙中,我忘记添加实际将用户与位置相关联的行。我已经纠正了错误。
  • 我不知道出了什么问题,但不幸的是它似乎没有解决问题:(抱歉:s
  • 您是否遇到任何错误。控制器接收的具体参数是什么?
  • 我看到它正在发送这个:“current_location_attributes”=>{“location”=>“葡萄牙波尔图”},不确定它是否应该具有位置的 :id...怎么做?我现在没有收到任何错误。
【解决方案2】:

您没有提供嵌套属性的 id。所以 Rails 认为这是一个新的。

- form_edit.fields_for :current_location do |location_form|
    = location_form.label :location, "Current Location"
    = location_form.text_field :location
    = location_form.hidden_field :id unless location_form.new_record?

【讨论】:

  • 您好。感谢您的快速回复。我已经添加了该字段,但同样的事情继续发生。它向表中添加了一个新位置。它不会为用户建立关联。所以 show.haml 永远不会显示 current_location :( 它总是空的。
【解决方案3】:

不确定前面的答案是否真的正确。您需要指定位置的用户 ID,而不是位置本身。

- form_edit.fields_for :current_location do |location_form|
  = location_form.label :location, "Current Location"
  = location_form.text_field :location
  = location_form.hidden_field :user_id

【讨论】:

  • 您好,感谢您的回复。当我添加该隐藏字段时,我收到以下错误消息: "undefined method `user_id' for #<0x54982c0>
【解决方案4】:

默认情况下,belongs_to :current_location, :class_name =&gt; 'Location' 将期望Users 表有一个current_location_id 字段。一旦你有了这个,你应该能够做类似的事情:

@user = @current_user
@user.update_attributes(params[:user])

@location = @user.current_location or @user.build_current_location
@location.update_attributes(params[:location]) 

@user.current_location.save!
@user.save!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2017-09-26
    • 2018-11-19
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多