1

In earlier versions of Rails it was possible to add dynamic attributes to a model without the need for there to be an SQL column. The following code worked pre 4.0.

drow = dtab1.drows.create()
drow.write_attribute('value1', 'xxx')
drow.write_attribute('value2', 'yyy')
drow.write_attribute('value3', 'zzz')

But now in v5 I get:

ActiveModel::MissingAttributeError: can't write unknown attribute `value1`

Is there any way to do that now?

Other answers have proposed predefined accessors or replacing the dynamic fields by a "user variables" hash, but that won't work for my situation. They need to be truly dynamic, created at runtime and treated as part of the model.

4
  • 1
    In earlier versions of Rails it was possible to add dynamic attributes to a model without the need for there to be an SQL column Can you point out a source for this please? AFAIK this is not possible. Commented Oct 17, 2018 at 6:11
  • Why accessors cannot do the job? They basically are ephemeral attributes. Commented Oct 17, 2018 at 9:28
  • @Pavan: Sorry, all I have is old code that works in Rails 2.1.2, and for some later version(s). Maybe it was never intended! Commented Oct 18, 2018 at 7:15
  • @Maxence: Perhaps they can. So what code would you write to solve my problem? Commented Oct 18, 2018 at 7:16

1 Answer 1

5

The write_attribute method updates the attribute in the underlying table. Since your new attributes are dynamic and do not match fields from your model table, no wonder it does not work.

To add attribute dynamically you need to declare it first, and then to call setter as for regular attribute. For example:

attr_name = 'value1'

# Declaring attr_accessor: attr_name
drow.instance_eval { class << self; self end }.send(:attr_accessor, attr_name)

drow.send(attr_name + '=', 'xxx')   # setter
drow.send(attr_name)                # getter

The property will be saved to the instance variable @value1.

The other way to save dynamic property is to alter that variable directly, without declaring attribute accessor:

drow.instance_variable_set("@#{attr_name}".to_sym, 'xxx') # setter
drow.instance_variable_get("@#{attr_name}".to_sym)        # getter
Sign up to request clarification or add additional context in comments.

3 Comments

that nearly looks like an answer, but it won't work as is. The attribute 'value1' only ever exists as a runtime string, so the last two lines cannot be compiled.
Aw, shame! My bad, sorry. I updated my answer, now it's truly dynamic. I also included an alternative method for setting a property dynamically.
Now that looks like an answer. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.