Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails ActiveRecord: Locking down attributes when record enters a particular state

Wondering if there’s a plugin or best way of setting up an ActiveRecord class so that, for example, when a record enter the "published" state, certain attributes are frozen so that they could not be tampered with.

like image 346
Gordon Isnor Avatar asked Nov 19 '09 20:11

Gordon Isnor


People also ask

What is the difference between Has_one and Belongs_to?

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.

Is ActiveRecord an ORM?

ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code.

What does ActiveRecord base do?

ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending. Edit: as Mike points out, in this case ActiveRecord is a module...

How do you lock in rails?

(lock = true) Link. Obtain a row lock on this record. Reloads the record to obtain the requested lock. Pass an SQL locking clause to append the end of the SELECT statement or pass true for “FOR UPDATE” (the default, an exclusive row lock).


2 Answers

If the particular state is merely persisted?, then attr_readonly is the best option.

attr_readonly(*attributes) public

Attributes listed as readonly will be used to create a new record but update operations will ignore these fields.

To test (courtesy of THAiSi):

class MyModel < ActiveRecord::Base
  attr_readonly :important_type_thingie
end

#RSpec
describe MyModel do
 its('class.readonly_attributes') { should include "important_type_thingie" }

 it "should not update the thingie" do
   m = create :my_model, :important_type_thingie => 'foo'
   m.update_attributes :important_type_thingie => 'bar'
   m.reload.important_type_thingie.should eql 'foo'
 end
end
like image 114
Turadg Avatar answered Oct 19 '22 16:10

Turadg


Editing attributes which shouldn't be edited is a validation error:

class Post < ActiveRecord::Base
  validate :lock_down_attributes_when_published

  private

  def lock_down_attributes_when_published
    return unless published?

    message = "must not change when published"
    errors.add(:title, message) if title_changed?
    errors.add(:published_at, message) if published_at_changed?
  end
end

This uses the ActiveRecord::Dirty extensions introduced in 2.2 or so.

like image 29
François Beausoleil Avatar answered Oct 19 '22 17:10

François Beausoleil