Non persistent ActiveRecord model attributes

后端 未结 5 1251
暗喜
暗喜 2020-12-10 00:20

I want to add to an existing model some attributes that need not be persisted, or even mapped to a database column. Is there a solution to specify such thing ?

相关标签:
5条回答
  • 2020-12-10 01:00

    In my case I wanted to use a left join to populate custom attribute. It works if I don't add anything but I also want to be able to set the attribute on a new object and of course it doesn't exist. If I add attr_accessor then it always returns nil after a select. Here's the approach I've ended up with that works for setting on new object and retrieving from left join.

    after_initialize do
      self.foo = nil unless @attributes.key?("foo")
    end
    
    def foo
      @attributes["foo"]
    end
    
    def foo=(value)
      @attributes["foo"] = value
    end
    
    0 讨论(0)
  • 2020-12-10 01:01

    I was having the same problem but I needed to bootstrap the model, so the attribute had to persist after to_json was called. You need to do one extra thing for this.

    As stated by apneadiving, the easiest way to start is to go to your model and add:

    attr_accessor :foo
    

    Then you can assign the attributes you want. But to make the attribute stick you need to change the attributes method. In your model file add this method:

    def attributes
      super.merge('foo' => self.foo)
    end
    
    0 讨论(0)
  • 2020-12-10 01:02

    Of course use good old ruby's attr_accessor. In your model:

    attr_accessor :foo, :bar
    

    You'll be able to do:

    object.foo = 'baz'
    object.foo #=> 'baz'
    
    0 讨论(0)
  • 2020-12-10 01:06

    In case anyone is wondering how to render this to the view, use the method arguments for the render method, like so:

    render json: {results: results}, methods: [:my_attribute]
    

    Please know that this only works if you set the attr_accessor on your model and set the attribute in the controller action, as the selected answer explained.

    0 讨论(0)
  • 2020-12-10 01:17

    From Rails 5.0 onwards you could use attribute:

    class StoreListing < ActiveRecord::Base
      attribute :non_persisted
      attribute :non_persisted_complex, :integer, default: -1
    end
    

    With attribute the attribute will be created just like the ones being persisted, i.e. you can define the type and other options, use it with the create method, etc.

    If your DB table contains a matching column it will be persisted because attribute is also used to affect conversion to/from SQL for existing columns.

    see: https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute

    0 讨论(0)
提交回复
热议问题