Rails: создайте атрибуты в определенном порядке - PullRequest
1 голос
/ 14 марта 2012

В моем приложении на Rails есть Пользователи.Пользователей просят указать их родной город и район / район.

class User < ActiveRecord::Base
  belongs_to :city
  belongs_to :district
end

class City < ActiveRecord::Base
  has_many :users
  has_many :districts
end

class District < ActiveRecord::Base
  has_many :users
  belongs_to :city
end

В формах я строю ассоциации, используя виртуальный атрибут в модели User, который принимает строку (дополнительную информацию ниже, если она уместна).

В консоли все это прекрасно работает, но в интерфейсе не работает.Кажется, проблема в том, что я могу получить city_name через форму без проблем, но когда я пытаюсь назначить город и район в одной и той же форме, всегда происходит сбой.Другими словами, массовое назначение не работает.

@user.update_attributes(params[:user])

Вместо этого, единственное, что мне удалось выяснить, - это вручную установить каждую клавишу из отправки формы, например:

@user.name = params[:user][:name] if params[:user][:name]
@user.city_name = params[:user][:city_name] if params[:user][:city_name]
@user.district_name = params[:user][:district_name] if params[:user][:district_name]

Этот подход работает, но это боль, отчасти хрупкая, и он чувствует себя все неправильно, потому что он начинает нагнетать контроллер с большой логикой.

Мой вопрос:

  1. Есть ли способ создания или обновления атрибутов в определенном порядке, в идеале в модели, чтобы контроллеру не приходилось беспокоиться обо всем этом?

  2. Я делаю это неправильно?Если так, то какой подход был бы лучше.


Дополнительная информация

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

Я хочу, чтобы пользователи могли выбирать город, просто введя имя, например «Чикаго, Иллинойс».Это прекрасно работает, используя виртуальный атрибут в пользовательской модели, например:

def city_name
  city.try :full_name
end

def city_name=(string)
  self.city = City.find_or_create_by_location_string( string )
end

Для пользователя имеет смысл только найти или создать район из города, который он выбрал.Это работает немного по-другому:

def district_name
  district.try :name
end

def district_name=(string)
  if self.city.nil?
    raise "Cannot assign a district without first assigning a city."
  else
    self.district = self.city.districts.find_or_create_by_name( string )
  end
end

В слое модели эти вещи работают нормально, если заданы как city_name, так и district_name, а районная ассоциация работает, как и ожидалось.

1 Ответ

1 голос
/ 14 марта 2012

Я думаю, вы могли бы сделать несколько вещей, чтобы очистить это.Во-первых, вы можете использовать делегатов для очистки кода.например,

delegate :name, :to => :city, :prefix => true, :allow_nil => true

таким образом вы можете сделать что-то вроде

user = User.create
user.city_name # nil
city = City.create(:name => 'chicago')
user.city = city
user.save
user.city_name # chicago

, и это будет просто работать.

Далее, я бы сказал, взять имя-идентификаторлогика из вашей модели.Вы можете сделать это либо в форме (например, поиск ajax помещает идентификатор района / идентификатор города в скрытое поле), либо в контроллере.Затем просто назначьте город / район как обычно.

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