Reputation:
As in, freeze
disables ability to update object values (to a degree). How might I build a method User.disable_persistence
that would disable ability to create/save/update on that object and associated objects, both called directly (User.save
) and indirectly (User.children << child
).
Is there a gem, or a simple method, like:
class User < ...
def disable_persistence
# magic here (nullify save, and other methods, prevent callbacks etc.)
class_eval :before_save do
errors.add(:base, "Persistence has been disabled for this object")
end
end
end
Upvotes: 3
Views: 815
Reputation: 239934
Try user.readonly!
>> u = User.last
=> ...
>> u.readonly!
=> true
>> u.save
User is marked as readonly (ActiveRecord::ReadOnlyRecord)
Upvotes: 2
Reputation: 7810
The problem seems simple. The tricky part though is the and indirectly (User.children << child)
part of it.
This can be dealt with easily when the parent object (User
) is new record. But not that easily if it is not.
This is because a statement like user#children << child
saves the parent record and the children
when record of user
is new
but does not do the same when it is not. On latter case it saves only the child
. This problem is not solved on
this project, automatically, at least for now. Developer has to disable the persistence on the child
object first
in order to achieve this on this latter case.
See the author_spec.rb
file. It is very helpful to tell you the whole story.
The whole project that I developed as task to answer your SOW question is here: https://github.com/pmatsinopoulos/disable_persistence
Anyone that wants to contribute on that, feel free.
The code that does the whole trick is quoted here too for readers convenience:
The disable_persistence.rb
file:
module DisablePersistence
extend ActiveSupport::Concern
def disable_persistence
@persistence_disabled = true
end
def enable_persistence
@persistence_disabled = false
end
module ClassMethods
def disable_persistence
@@class_persistence_disabled = true
end
def enable_persistence
@@class_persistence_disabled = false
end
def persistence_disabled?
@@class_persistence_disabled ||= false
end
def persistence_disabled
persistence_disabled?
end
end
included do
attr_reader :persistence_disabled
alias :persistence_disabled? :persistence_disabled
before_save :can_persist?
after_initialize do |base|
base.instance_variable_set(:@persistence_disabled, false)
end
def can_persist?
!persistence_disabled? && !self.class.persistence_disabled?
end
protected :can_persist?
end
end
ActiveRecord::Base.send :include, DisablePersistence
Notes:
A. The instances will be responding to:
#disable_persistence
#enable_persistence
#persistence_disabled?
B. The class will be responding to:
#disable_persistence
#enable_persistence
#persistence_disabled?
C. There is a protected
before_save
method that checks whether the instance can persist. It check that both instance and class persistence are enabled. If any is disabled, does not allow the instance to persist.
D. The functionality is automatically included in all ActiveRecord::Base
classes. This is the last line above. You may not want that. If you do not want that, you have to call include DisablePersistence
on all your ActiveRecord::Base
classes that you want this feature on.
E. In the rails project that I link to, I have an initializer
that require
s the file that contains this code. Look into the config/initializers
. Otherwise, you will have to require it yourself.
Some examples of usage (Assume an author and their books):
First example:
author = Author.new
author.disable_persistence
author.save # will return false and nothing will be saved
author.enable_persistence
author.save # will return true and author will be saved
Second example:
author = Author.new
author.disable_persistence
book = Book.new
author.books << book
author.save # false and nothing will be saved
Third example:
author = Author.new
author.save
book = Book.new
book.disable_persistence
author.books << book # nothing will be saved
Fourth example:
author = Author.new
author.save
book = Book.new
author.disable_persistence
author.books << book # will be saved indeed, because the book has enabled persistency
Fifth example:
author = Author.new
Author.disable_persistence
author.save # will return false and will not save
I hope the above answers your question, or at least is helpful somehow.
Upvotes: 2
Reputation: 1978
You can create a Transaction and throw an Exception for Rollback any changes.
Upvotes: 1
Reputation: 4976
You could add a before_save
filter to check for the value of a boolean field (say editable
) that redirects to the root url if set to false. The block will end before the the create/save/update
methods are called.
Upvotes: 2