Почему связанный объект не сохраняется? - PullRequest
2 голосов
/ 24 октября 2010

У меня есть рубиновый (на рельсах) класс:

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 - почему адрес не сохраняется?

Как я могу изменить этот код так, чтобы адрес был сохранен (как я и ожидал)?

Я запускаю это под ruby ​​на рельсах 3.

Спасибо!

Ответы [ 5 ]

0 голосов
/ 24 октября 2010

Попробуйте:

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
0 голосов
/ 24 октября 2010

Кажется, проблема в том, что адрес на самом деле не удалось сохранить.не из-за проверки, а из-за ошибки в методе 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!Лично я думаю, что это небольшая ошибка, возможно, или, конечно, неожиданное поведение, но что я знаю!

0 голосов
/ 24 октября 2010

Вы должны сказать ему, что такое внешний ключ, если вы не придерживаетесь стандартной структуры таблицы. Вам просто нужно добавить:

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

или любой другой столбец, который вы используете для сохранения идентификатора адреса в таблице адресов.

Это не рекомендуемый способ создания вложенных атрибутов. Я бы рекомендовал использовать fields_for в вашей форме, а не использовать строки:

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

Вы можете просто сделать

<% = f.fields_for: current_shipping_address do | ff | %> # ... поля вашего адреса ... <% end%>

, который позволит вам просто сохранить адрес при запуске @user.save!

Вы все еще можете добавить :country => "US" заранее с помощью

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

и затем запустите сохранение. Хотя это действительно зависит от вас.

0 голосов
/ 24 октября 2010

Попробуйте вот так!

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!
0 голосов
/ 24 октября 2010

Вы не можете сохранить подписку и current_shipping_address пользователем в вашем случае, потому что они не являются простыми полями в модели User.Вы определяете их как модель, ассоциированную с Пользователем через own_to, я не уверен, что вы готовы делать, но если я правильно понимаю, один из способов сделать это - использовать вложенные атрибуты:, когда вы затем создаете и сохраняете пользователя, подписка и current_shipping_address сохраняются вместе с ним.

Подробнее о связях здесь: http://guides.rubyonrails.org/association_basics.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...