(Puedes ver la versión original de este post en español
aquí)
I was looking for a
Rails plugin to handle the settings (preferences, options, etc.) of a web application I’m working on.
In the
Rails wiki I found this
ConfigurationGenerator that looked pretty neat, and was exactly what I wanted, but I couldn’t find the code anywhere, nor have I received an answer to a
question a posted in the
Rails forum about this generator.
Then I found this other
Settings plugin that looked great, but it wasn’t quite what I needed.
So I decided to make my own model to handle the settings of my web application, based in what I’ve already seen in these plugins.
What I wanted was a table with a unique row and a column for every option in the settings. This would let me save every option with the right data type and size. And I wanted to be able to access any setting, from any place in the application, with something as simple as:
Settings.option
I started with the settings for the application name and a "about us" text for the home page. The migration looked like:
class AddSettings < ActiveRecord::Migration
def self.up
create_table :settings do |table|
table.column :aplication, :string, :limit => 100
table.column :about_us, :text
table.column :updated_at, :datetime
end
execute "Insert into settings (aplication, about_us) Values ('Web app.', 'We are...')"
end
def self.down
drop_table :settings
end
end
This table will always have a unique, so one row is inserted automatically in the migration, with samples values. The real values will be assigned in the application.
The model looked like:
class Setting < ActiveRecord::Base
validates_presence_of : aplication, :about_us
private_class_method :new, :create, :destroy, :destroy_all, :delete, :delete_all
@@s = find(:first)
def self.method_missing(method, *args)
option = method.to_s
if option.include? '='
# Set the value
var_name = option.gsub('=', '')
value = args.first
@@s[var_name] = value
else
# Get the value
@@s[option]
end
end
def self.save
@@s.save
end
def self.update_attributes(attributes)
@@s.update_attributes(attributes)
end
def self.errors
@@s.errors
end
end
I would use the class directly, without an instance of it, so I had to avoid the creation of new objects with the line private_class_method :new, :create
. To this list I added :destroy, :destroy_all, :delete, :delete_all
because I certainly didn’t want that unique row to be deleted. This list can be extended to add any other method we want to deny access to.
I don’t want to go to the database every time I need a setting, so I use a class variable to cache the setting values the first time the class was used: @@s = find(:first)
The methods save
, update_attributes
and errors
are defined as class methods, with self
, to be able to called them without the need of an instance of the class.
You can assign the setting’s value one by one, and call the save
method at the end, so there would be only one update operation in the database. Or you can call the update_attributes
with a hash as parameter, with all the settings values to save (when saving from a form, for example). The method errors
is defined to be able to use the error_messages_for 'settings'
helper in a form.
To edit the settings you can use something like the following code. In the appropriate controller:
def settings
@settings = Settings
end
def save_settings
@settings = Settings
if @settings.update_attributes(params[:settings])
flash[:notice] = 'Settings successfully saved'
redirect_to :action => "index"
else
render :action => "settings"
end
end
And in the view:
<h1>Settings</h1>
<br>
<%= start_form_tag :action => 'save_settings' %>
<%= error_messages_for 'settings' %>
<p><label for="settings_aplication">Application:</label><br/>
<%= text_field_tag 'settings[aplication]', @settings.aplication %></p>
<p><label for="settings_about_us">About us:</label><br/>
<%= text_area_tag "settings[about_us]", @settings.about_us %></p>
<br>
<%= submit_tag 'Save' %>
<%= end_form_tag %>
This is what suits my need the best way so far. If there is a better way to do this I’d be happy to hear it.
Like this article? Digg it!
... read more