Ruby on Rails的:嵌套的属性,belongs_to的关系 [英] Ruby on Rails: Nested Attributes, belongs_to relation

查看:147
本文介绍了Ruby on Rails的:嵌套的属性,belongs_to的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有当前位置字段(城市和国家)的用户实体。旧此信息,我创建了一个名为位置的实体,HAS_MANY用户。

我不能完全肯定我是否应该把在用户模式HAS_ONE或belongs_to的,但我读,如果我想它有位置的外键,我应该把belongs_to的。我也希望能够编辑用户时,编辑用户的当前位置。所以我使用嵌套的属性。但是,当我编辑的用户我最终每次添加一个新的位置而没有它关联到被编辑的用户。你能帮我吗?

我的code是以下内容:

 #用户模式
类User< ActiveRecord的::基地
  ##的关系
  belongs_to的:CURRENT_LOCATION,:CLASS_NAME => '位置'
  accepts_nested_attributes_for:CURRENT_LOCATION
结束#Location型号
一流的位置和LT; ActiveRecord的::基地
  #关系
  的has_many:用户
结束在_form_edit.haml的一部分#
- form_edit.fields_for:CURRENT_LOCATION做| location_form |
  = location_form.label:位置,当前位置
  = location_form.text_field:位置#Application助手
#nested属性用户和位置
高清setup_user(用户)
  返回(用户)做| U |
    u.build_current_location如果u.current_location.nil?
  结束
结束#in用户控制器(编辑后加入)
DEF更新
    @user = @current_user
    如果@ user.update_attributes(PARAMS [:用户])
      闪光[:通知] =帐户已更新!
      redirect_to的account_url
    其他
      渲染:行动=> :编辑
    结束
  结束


解决方案

你面对,正如其他人指出确切的问题是,您的控制器未接收到的位置ID,因为它应该。看来我的位置ID是通过错误的参数传递。不幸的是一个位置id不上一个新的记录存在,所以这是不可能的形式

您的问题从一个belongs_to的关系,利用accepts_nested_attributes_for茎。该行为没有明确的规定。这似乎是一个文档的错误。所以accepts_nested_attributes_for应该是一个具有一个或有关系的许多侧

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


  1. 移动accepted_nested_attributes_for的选址模型和周围建立表单的其他方式。

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

    不幸的是这不允许的presenting信息的逻辑方法。和使编辑正确的用户困难。


  2. 使用一个连接模型,并进行了有一个:通过关系

    我真的不知道如何accept_nested_attributes_for与工程:通过关系,但它肯定会带有链接的记录您解决问题。


  3. 忽略accepts_nested_attributes_for和处理该协会在控制器的老式方法。

    其实保持accepts_nested_attributes_for。它提供了一些方便的便利的方法,就是不让它给update_attributes方法/ create语句。

      DEF更新
      @user = @current_user
      完成= FALSE
      location_params =参数[:用户] .delete(:current_location_attributes)
      User.transaction做
        @location = Location.find_or_create_by_id(location_params)
        @ user.update_attributes(PARAMS [:用户])
        @ user.current_location = @location
        @ user.save!
        完成=真
      结束
      如果完成
        闪光[:通知] =帐户已更新! redirect_to的account_url
      其他
        渲染:行动=> :编辑
      结束
    结束


用于将填充在current_location_attributes ID字段

字段自动哈希,如果它不创建一个新的位置。然而,find_or_create_by_id,需要:在散列为它工作证进入。它将与一个正确的自动递增标识创建如果ID是不在数据库中。如果要创建一个新的位置,你将需要添加它。最简单的将其添加到与 = location_form.hidden_​​field形式:ID,0,除非当前\\ _location.new \\ _Record ?。

不过,您可能要减少重复位置的创建和Location.find_or_create_by_id线改为Location.find_or_create_by_location。这也会从失败的唯一性验证减少任何错误。

I have a User entity that has a Current Location field (city and country). To old this info I created an entity called Location which has_many Users.

I'm not entirely sure if I should put in the User model "has_one" or "belongs_to", but for what I read if I wanted it to have the foreign key of the location I should put "belongs_to". I also want to be able to edit the user's Current Location when editing the User. so I am using nested attributes. But when I edit the user I end up adding a new Location each time without ever associating it to the user that was edited. Can you help me out?

My code is the following:

#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

解决方案

The exact problem you're facing, as others have pointed out is that your controller is not receiving the location id as it should. Looks to me the location id is being passed through the wrong parameter. Unfortunately a location id doesn't exist on a new record, so this is not possible in the form.

Your problem stems from the use accepts_nested_attributes_for on a belongs_to relationship. The behaviour isn't clearly defined. This appears to be a documented bug. So the accepts_nested_attributes_for should be on a has one or has many side of a relationship.

Here are some possible solutions:

  1. Move The accepted_nested_attributes_for to the Location model and build your forms the other way around.

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

    Unfortunately this doesn't allow for a logical way of presenting information. And makes editing the right user difficult.

  2. Use a join model, and make a has one :through relationship.

    I'm honestly not sure how well accept_nested_attributes_for works with a :through relationship, but it will definitely solve your problem with linking records.

  3. Ignore accepts_nested_attributes_for and handle the association in your controller the old fashioned way.

    Actually keep the accepts_nested_attributes_for. It provides some handy convenience methods, just don't let it get to the update_attributes/create statement.

    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 will populate an id field in the current_location_attributes hash automatically, if it's not creating a new location. However, find_or_create_by_id, requires an :id entry in the hash for it to work. It will create with a correctly auto incremented id if the id isn't in the database. If you are creating a new location you will need to add it. Easiest to add it to the form with =location_form.hidden_field :id, 0 unless current\_location.new\_record?.

However, you might want to cut down on duplicate location creation, and change the Location.find_or_create_by_id line to Location.find_or_create_by_location. This will also cut down on any errors from failed uniqueness validations.

这篇关于Ruby on Rails的:嵌套的属性,belongs_to的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆