问题
I have a somewhat special use case, where I'd like to create a method that accepts a block, such that anything that happens inside that block is not written to the DB.
The obvious answer is to use transactions like so:
def no_db
ActiveRecord::Base.transaction do
yield
raise ActiveRecord::Rollback
end
end
But the trouble is that if my no_db method is used inside of another transaction block, then I'll ned up in the case of nested transactions. The drawback here is that nested transactions are only supported by MySQL, and I need support for PG, but more importantly SQLite (for tests). (I understand that PG is supported via savepoints, how reliable is that? performance hit?).
The other problem with this type of approach is that it seems really inefficient, writing things to a DB, and then rolling them back. It would be better if I could do something like this:
def no_db_2
# ActiveRecord::Base.turn_off_database
yield
# ActiveRecord::Base.turn_on_database
end
Is there such a method? Or a similar approach to what I'm looking for? I think it needs to be fairly low level..
(Rails version is 3.0.5, but I would be happy if there were an elegant solution for Rails 3.1)
回答1:
This might be one way to do it:
class Book < ActiveRecord::Base
# the usual stuff
end
# Seems like a hack but you'll get the
# transaction behavior this way...
class ReadOnly < ActiveRecord::Base
establish_connection "#{Rails.env}_readonly"
end
I would think that this...
ReadOnly.transaction do
Book.delete_all
end
...should fail.
Finally, add another connection to config/database.yml
development:
username: fullaccess
development_readonly:
username: readonly
One downside is the lack of support for a read-only mode in the sqlite3-ruby driver. You'll notice that the mode parameter doesn't do anything yet according to the documentation. http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html#M000071
来源:https://stackoverflow.com/questions/7492099/how-can-i-prevent-activerecord-from-writing-to-the-db