如何在呈现ActiveRecord实例之前修改其属性

时间:2018-11-02 17:46:27

标签: ruby-on-rails ruby

在我的Rails项目中,我有一个模型class Employee < ActiveRecord::Base,该类具有名为 compensation 的属性,它是Postgresql中的:jsonb数据类型。

  create_table "employee" do |t|                       
    ...
    t.jsonb    "compensation"
    ...
  end

薪酬包含薪水,工作时间,起始时间等

compensation : {
  salary: 50000,
  working_hours: 230,
  start_from: 2018-12-21,
  ...
}

我想做的是,在将Employee实例呈现为JSON并响应前端之前,我需要删除薪酬中的薪水属性。在employee_controller中,我尝试使用

def get_without_salary
  employee = Employee.find 2
  employee.compensation.delete :salary
  jsonapi_render json: employee
end

,但结果JSON仍包含薪水数据。 我只能通过以下方式使其起作用:

  temp_compensation = employee.compensation.dup
  temp_compensation.delete :salary
  employee.compensation = temp_compensation

但这太丑陋,使我困惑为什么第一种方法失败了。

有人可以向我解释为什么吗?谢谢

2 个答案:

答案 0 :(得分:0)

这似乎是一个棘手的问题。 as_json的选项如下:

  1. includes: =>过去包括has_manybelongs_to关联
  2. methods: =>包含模型的类方法的结果
  3. except: =>防止显示showig列
  4. only: =>仅显示指定的列

我尝试其中的一些方法仅指定jsonb列的某些属性,但是它们不起作用或抛出NoMethodError: undefined method 'serializable_hash' for #<Hash:0x00000005082eb0>,表明它试图序列化jsonb但失败。 / p>

我认为一种干净的方法可能是在模型中有一个方法filtered_compensation,在其中定义要发送的json并阻止显示compensation

def get_without_salary
  employee = Employee.find 2
  jsonapi_render json: employee.as_json(methods: [:filtered_compensation], except: [:compensation])
end

在模型中声明filtered_compensation的地方

def filtered_compensation
  compensation.except 'salary'
end

我认为这样做符合清洁,分离问题的原则,并使您的方法filtered_compensation可以在其他地方使用。

  

请注意,您将发现compensation而不是在响应中添加属性filtered_compensation,因为它是方法的名称。

答案 1 :(得分:0)

经过几天的思考,我提出了一个解决方案,该解决方案首先将active_record实例转换为哈希,然后删除哈希中的薪水,然后将哈希转换为active_record实例。与动态更改对象相比,这是一个更好的解决方案。

def get_without_salary
  employee = Employee.find 2
  filtered_employee = filter_salary employee
  jsonapi_render json: filtered_employee
end

def filter_salary(employee)
  record_hash = employee.as_json.deep_symbolize_keys!
  record_hash[:compensation]&.delete :salary
  Employee.new(record_hash)
end