I have an interactive Ruby on Rails application which I would like to put into a "read only mode" during certain times. This will allow开发者_如何学Go users to read the data they need but block them from actions that write to the database.
One way to do this would be to have a true/false variable located in the database that was checked before any write was made.
My question. Is there a more elegant solution for this problem out there?
If you really want to prevent any database write, the easiest way I can imagine would be to override the readonly?
method of a model to always return true, either in selected models or maybe even for all ActiveRecord models. If a model is set to readonly (normally done by calling #readonly!
on it), any try to save the record will raise an ActiveRecord::ReadOnlyRecord
error.
module ActiveRecord
class Base
def readonly?
true
end
end
end
(actually untested code, but you get the idea…)
Another good one which I liked a little better is Declarative Authorization which is covered by Railscasts as well: Railscasts - Declarative Authorization
Permissions plugin? Something simple like cancan where you define what a user can do, when. It will allow you to display links, or not, and restrict access to controller actions. The railscast will explain better than I can.
http://github.com/ryanb/cancan
http://railscasts.com/episodes/192-authorization-with-cancan
Zargony's solution seems to be the best one, but I would like to add to it a bit.
So, about his code:
This works nicely. A good solution is to add this in an initializer and run this code only if an env var is set, so that you can choose whether to run the app in read-only mode on launching the app.
if ENV['READ_ONLY'] == 'true'
module ActiveRecord
class Base
def readonly?
true
end
end
end
end
And then run the server from command prompt like READ_ONLY=true bin/rails s
. Also, adding
rescue_from ActiveRecord::ReadOnlyRecord, with: ->() {
flash[:alert] = "The site is running in read-only mode. We are going to return to full operation soon. Thank you for your patience!"
redirect_to root_path
}
to the ApplicationController (that all of your controllers should inherit from) is a nice way to show the users what is going on.
The answer by Zargony will work well but raise an exception if your application is trying to write anything. If you want your application to fail silently on writes so that it doesn't show error pages on each operation (e.g. if you update a timestamp on login in your code, you will get an exception), you can use the approach below:
unless Rails.env.test?
class ActiveRecord::Base
before_save do
raise ActiveRecord::Rollback, "Read-only"
end
before_destroy do
raise ActiveRecord::Rollback, "Read-only"
end
end
end
精彩评论