Search code examples
ruby-on-railsruby-on-rails-3type-conversionactivemodel

Casting ActiveModel attribute on return


In my Rails 3.1.1 project I have an ActiveModel that talks to API (ripped from Paul Dix's book, shortened for readability):

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

I instantiate @job in my controller, new action (company_id is a segnment key in the route: /companies/:company_id/jobs/new) like this:

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

Then, using CanCan, I check user's permissions to create to create a job. Basically, CanCan checks if current_user's company_id attribute matches job's company_id. This check fails because @job.company_id is returned as String.

Certainly, I can use params[:company_id].to_i while instantiating the object, but this seems like a workaround that I would have to repeat later.

Question: is there a way to make my Job ActiveModel more "type-aware" and make it return int for @job.company_id call?

I googled around, checked activemodel source code, but doesn't seem to find an answer. Any help is greatly appreciated.

Update I was thinking more of something like schema block for ActiveModel, just like the one in ActiveResource.


Solution

  • attr_accessor *ATTRIBUTES
    

    create a method like this:

    def company_id
      @company_id
    end
    

    You can just override that with

    def company_id
      @company_id.to_i
    end