【问题标题】:Casting ActiveModel attribute on return在返回时强制转换 ActiveModel 属性
【发布时间】:2011-10-27 17:25:39
【问题描述】:

在我的 Rails 3.1.1 项目中,我有一个与 API 对话的 ActiveModel(摘自 Paul Dix 的书,为便于阅读而缩短了):

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

我在我的控制器中实例化@jobnew 动作(company_id 是路由中的一个段键:/companies/:company_id/jobs/new),如下所示:

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

然后,使用 CanCan,我检查用户的创建权限以创建作业。基本上,CanCan 检查 current_user 的 company_id 属性是否与作业的 company_id 匹配。此检查失败,因为 @job.company_id 作为字符串返回。

当然,我可以在实例化对象时使用 params[:company_id].to_i,但这似乎是一种我以后必须重复的解决方法。

问题:有没有办法让我的 Job ActiveModel 更加“类型感知”,并让它为 @job.company_id 调用返回 int?

我四处搜索,检查了activemodel 源代码,但似乎没有找到答案。非常感谢任何帮助。

更新 我正在考虑更多类似于 ActiveModel 的 schema 块,就像 ActiveResource 中的块一样。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 type-conversion activemodel


    【解决方案1】:
    attr_accessor *ATTRIBUTES
    

    创建一个这样的方法:

    def company_id
      @company_id
    end
    

    你可以用

    覆盖它
    def company_id
      @company_id.to_i
    end
    

    【讨论】:

    • 我在考虑它,但这意味着我必须对模型中的所有 int 属性做同样的事情。它绝对比在控制器中使用.to_i 更优雅。如果我不能得到更好的回应,你的将被接受。感谢您的宝贵时间。
    【解决方案2】:

    回答我自己的问题....

    mosch 的回答建议在我的 ActiveModel 中覆盖 company_id 的 getter。但是,我必须对模型中的所有 _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
    

    【讨论】:

      【解决方案3】:

      我假设您的公司has_many => :jobs?如果是这样,你可以试试

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

      【讨论】:

      • Company 和 Job 都是 ActiveModel,因此,传统的 has_manybelongs_to 在这里不工作...
      猜你喜欢
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多