为什么关联对象不能保存?

时间:2010-10-23 21:01:02

标签: ruby-on-rails activerecord ruby-on-rails-3

我有一个红宝石(在轨道上)类:

class User < ActiveRecord::Base
  # relationships
  belongs_to :current_shipping_address, :class_name => "Address"
  belongs_to :subscription

  # Validators
  validates_presence_of :subscription
  validates_presence_of :current_shipping_address
end

我在控制器中执行此操作:

subscription = Subscription.new

address_info = params[:user].delete(:address) rescue {}
@address = Address.new(address_info.merge(:country => "US"))

@user = User.new(params[:user].merge(:first_name => @address.first_name, :last_name => @address.last_name))
@user.subscription = subscription
@user.current_shipping_address = @address
@user.save!

此时,令人难以置信的是,我有一个@user已保存在数据库中但没有current_shipping_address(尽管有验证)。订阅也已保存在数据库中。

地址不会被保存。

我在这里缺少什么? 1 - 如果没有验证失败,用户如何保存? 2 - 为什么地址没有保存?

如何更改此代码以便保存地址(正如我所期望的那样)?

我在rails 3上的ruby下运行它。

谢谢!

5 个答案:

答案 0 :(得分:0)

在您的情况下,用户无法保存订阅和current_shipping_address,因为它们不是模型用户中的简单字段。您通过belongs_to将它们定义为与User相关联的模型,我不确定您愿意做什么,但如果我理解正确,则使用嵌套属性:

class User < ActiveRecord::Base
  # relationships
  has_many :current_shipping_addresses, :class_name => "Address", :dependant => destroy
  has_many :subscriptions, :dependant => destroy


  # Nesting
  accepts_nested_attributes_for :subscriptions
  accepts_nested_attributes_for :current_shipping_addresses

end

之后,当您创建并保存用户时,会保存订阅和current_shipping_address。

有关此处关联的更多信息:http://guides.rubyonrails.org/association_basics.html

答案 1 :(得分:0)

如果您不遵守标准表结构,则需要告诉它外键是什么。你只需要添加:

belongs_to :current_shipping_address, :class_name => "Address", :foreign_key => "address_id"

或用于将地址ID存储到地址表的任何列。

这不是建议的嵌套属性的方法。我建议您在表单中使用fields_for而不是使用以下行:

address_info = params[:user].delete(:address) rescue {}
@address = Address.new(address_info.merge(:country => "US"))

你可以做到

&lt;%= f.fields_for:current_shipping_address do | ff | %GT;       #...您的地址字段......    &lt;%end%&gt;

然后您可以在运行@user.save!

时简单地保存地址

您仍然可以事先添加:country => "US"

params[:user][:current_shipping_address][:country] = "US"

然后运行save。它真的取决于你。

答案 2 :(得分:0)

试试这种方式!

subscription = Subscription.new

address_info = params[:user].delete(:address) rescue {}

@user = User.new(params[:user].merge(:first_name => @address.first_name, :last_name => @address.last_name))
@user.subscription = subscription
@user.current_shipping_address << Address.new(address_info.merge(:country => "US"))
@user.save!

答案 3 :(得分:0)

似乎问题是地址实际上无法保存。不是因为验证而是因为'before_create'方法中的错误(是的,我知道我没有给你地址对象......我当时认为它不重要!)。

class Address < ActiveRecord::Base
  # relationships

  # Validators
  validates_presence_of :city, :state, :country, :first_name, :last_name, :address_1

  before_create :check_state
  before_create :check_country

  def check_state
    retval = true
    state.upcase!
    if country == "US" and !US_STATES.map{|s| s[1]}.include?(state)
      errors.add(:state, "Must be valid")
      retval = false
    end

    retval
  end
end

检查状态是否失败。但这意味着该地址通过了'有效?'电话,这似乎是所有积极的记录关心。 (这种方法确实应该是一种验证)

我已经切换到这样做了(感谢enokd的链接!):

@user = User.new(params[:user].merge(:first_name => @address.first_name, :last_name => @address.last_name))
@user.build_subscription(:subscription_plan_id => @subscription_plan.id)
@user.build_current_shipping_address(address_info.merge(:country => "US")) 

我没有费心去完全调查,但是,如果地址无法保存,它将停止整个@ user.save! 就我个人而言,我认为这可能是一个小小的错误或肯定是一个意想不到的行为,但我知道什么!

答案 4 :(得分:0)

尝试:

class User < ActiveRecord::Base
  # relationships
  has_one :current_shipping_address, :class_name => "Address", :dependant => destroy
  has_many :subscriptions, :dependant => destroy

  validates :current_shipping_address, :presence => true
end