Ignore read-only column when creating and updating in Ruby ActiveRecord

I am looking for a solution to the following problem: I have an ActiveRecord object that is supported by an updated database view (in DB2 using the activerecord-jdbc-adapter harness). This view contains one column, which is calculated from other columns and is read-only: you cannot set this column in any real way. When a new record is created for this object, this field should not be set. However, by default, ActiveRecord sets it with a "default" (NULL), which is rejected by the database.

attr_readonly is not a solution, as it only excludes columns from updates, not creates.

attr_ignore, for example, implemented by the Lincoln pearl, is also not a solution, because then the field is completely ignored. However, the column still needs to be read and accessible. It is actually even used as part of a relationship.

There are ways to prevent the setting of a specific attribute of an ActiveRecord object, but usually this does not prevent the inclusion of this attribute in create or update statements.

Does anyone know if there is a way in ActiveRecord to specify a column as "never set this field"?

Update in response to Arsen7: I tried using hook after initialization to remove the attribute from the newly created object, so it is not included in the built SQL. The problem is that the attribute is completely removed and inaccessible at all, largely identical to the igonre_attr situation described above. Due to caching, this is not trivial to work around and will require additional logic to force the reloading of the entities of these specific tables. This can probably be achieved by overriding createto add a "reload" in addition to using the after_initialize parameter.

(As Arsen7 noted, I forgot to mention that I am in ActiveRecord 3.0.9)

My decision

ActiveRecord::Base, before_create after_create. hook before_create "" @attributes . hook after_create "" , , .

create, , Arsen7 .

+5
3

, ActiveRecord . (: AR ?)

, .

-, "create" , - SQL, . , , , "", , , .

, , , . PostgreSQL, 'CREATE RULE', , DB2, , DB2 " OF" . , .

+2

, ActiveRecord:: Base # arel_attributes :

Class Model < ActiveRecord::Base
  @@skip_attrs = [:attr1, :attr2]     

  def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
    skip_attrs = @@skip_attrs.map { |attr| [self.class.arel_table[attr] }
    attrs = super(include_primary_key, include_readonly_attributes, attribute_names)
    attrs.delete_if {|key, value| skip_attrs.include?(key) }         
  end 
end

@@skip_attrs ActiveRecord insert, update, isl_attributes_values ​​ .

: ActiveRecord:: Base # isl_attributes attr_ignore, attr_readonly.

+2

, , . , . AR, , .

CREATE TRIGGER incr_col_idx
AFTER INSERT ON fl_format_columns
FOR EACH ROW
BEGIN UPDATE fl_format_columns
SET idx = (SELECT coalesce(max(idx),-1) + 1
           FROM fl_format_columns
           WHERE fl_file_format_id = new.fl_file_format_id)
WHERE fl_file_format_id = new.fl_file_format_id AND name = new.name;
END;

, .

# @raise ArgumentError when an attempt is made to set a value that is calculated in db
def idx=(o)
  raise ArgumentError,'the value of idx is set by the db. attempts to set value is not allowed.' unless o.nil?
end

, , , . :

context 'column index' do
  it 'should prevent idx from being set' do
    expect{FL_Format_Column.create(fl_file_format_id:-1,name:'test idx',idx:0)}.to raise_error(ArgumentError)
  end
  it 'should calculate idx relative to zero' do
    x = FL_Format_Column.create(fl_file_format_id:-1,name:'test_idx_nil')
    expect(x.errors[:idx].any?).to be false
    expect(FL_Format_Column.last.idx).to be > -1
  end
end
0

All Articles