Приведение атрибута ActiveModel по возвращении - PullRequest
1 голос
/ 27 октября 2011

В моем проекте Rails 3.1.1 у меня есть ActiveModel, который взаимодействует с API (извлечено из книги Пола Дикса, сокращено для удобства чтения):

class Job
  include ActiveModel::Validations
  include ActiveModel::Serializers::JSON

  ATTRIBUTES = [ :id,
                 :title,
                 :description,
                 :company_id ]

  attr_accessor *ATTRIBUTES

  validates_presence_of     :title, :description
  validates_numericality_of :company_id, :id

  def initialize(attributes = {})
    self.attributes = attributes
  end

  def attributes
    ATTRIBUTES.inject(
      ActiveSupport::HashWithIndifferentAccess.new
      ) do |result, key|

      result[key] = read_attribute_for_validation(key)
      result
      end
  end

  def attributes=(attrs)
     attrs.each_pair {|k, v| send("#{k}=", v)}
  end

  def read_attribute_for_validation(key)
    send(key)
  end

  # More method definitions...
end

Я создаю @job в моем контроллере, new действие (company_id - это ключ сегмента в маршруте: /companies/:company_id/jobs/new), например:

@job = Job.new(company_id: params[:company_id])

Затем, используя CanCan, я проверяю права пользователя для создания и создания вакансии. По сути, CanCan проверяет, соответствует ли атрибут company_id current_user заданию company_id. Эта проверка завершается неудачно, потому что @job.company_id возвращается как String.

Конечно, я могу использовать params [: company_id] .to_i при создании экземпляра объекта, но это похоже на обходной путь, который мне придется повторить позже.

Вопрос: есть ли способ сделать мою ActiveModel для работы более «типизированной» и заставить ее возвращать int для @job.company_id вызова?

Я погуглил, проверил activemodel исходный код, но, похоже, не нашел ответа. Любая помощь с благодарностью.

Обновление Я больше думал о блоке schema для ActiveModel, как в ActiveResource.

Ответы [ 3 ]

1 голос
/ 27 октября 2011
attr_accessor *ATTRIBUTES

создайте метод, подобный этому:

def company_id
  @company_id
end

Вы можете просто переопределить это с помощью

def company_id
  @company_id.to_i
end
1 голос
/ 28 октября 2011

Отвечая на мой собственный вопрос ....

В ответе Моша предложено переопределить метод получения для company_id в моей ActiveModel.Однако мне пришлось бы повторить это для всех атрибутов _id в модели.Поэтому я решил привести все атрибуты _id к целым числам при инициализации объекта.Следующим образом:

def attributes=(attrs)
    attrs.each_pair do |k, v|
      if "#{k}".include? "_id"
        send("#{k}=", v.to_i)
      else
        send("#{k}=", v)
      end
    end
end
0 голосов
/ 27 октября 2011

Я предполагаю, что ваша компания has_many => :jobs? Если это так, вы можете попробовать

def new
  @company = Company.find(params[:company_id])
  @job = @company.jobs.new
end
...