Skip to content

Instantly share code, notes, and snippets.

@doitian
Forked from masqita/type_caster.rb
Created December 16, 2012 13:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doitian/4307089 to your computer and use it in GitHub Desktop.
Save doitian/4307089 to your computer and use it in GitHub Desktop.
Add a active model wrapper to edit settings in form. `type_caster.rb` can be put in lib directory, which convert the field to specific type. The wrapper idea also can be used to wrap any other object, such as [Railscasts #396](https://github.com/railscasts/396-importing-csv-and-excel/blob/master/store-with-validations/app/models/product_import.rb)
<h1>Settings</h1>
<%= simple_form_for @settings, :as => 'settings', :url => admin_settings_path, :html => { :class => 'form form-horizontal' } do |f| %>
<fieldset>
<legend>Points Earning</legend>
<%= f.input :site_name %>
<%= f.input :per_page %>
</fieldset>
<div class="control-group">
<div class="controls">
<%= f.submit 'Update', :class => 'btn btn-primary' %>
</div>
</div>
<% end %>
# Use type_caster to edit settings using form builder
#
# gem: https://github.com/huacnlee/rails-settings-cached
class Settings < RailsSettings::CachedSettings
attr_accessible :var
class Fields
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
include TypeCaster
field :site_name, :string
field :per_page, :integer
validates :per_page, :numericality => { :greater_than => 0 }
def initialize(attributes = {}, settings = Settings)
@settings = settings
@attributes = attributes.with_indifferent_access
end
def new_record?
false
end
def persisted?
true
end
def load
@attributes = HashWithIndifferentAccess.new
self.class.fields.each do |name, caster|
self.send "#{name}=", @settings.send(name)
end
self
end
def save!
raise ActiveRecord::RecordInvalid unless valid?
save
end
def save
return false unless valid?
attributes.each do |name, value|
if self.class.fields.key?(name.to_sym)
@settings.send "#{name}=", read_attribute(name)
end
end
self
end
end
end
class SettingsController < ApplicationController
def edit
@settings = Settings::Fields.new
@settings.load
end
def update
@settings = Settings::Fields.new(params[:settings])
if @settings.save
redirect_to edit_settings_path, :notice => 'Settings were successfully updated'
else
render :edit
end
end
end
module TypeCaster
def self.included(klass)
klass.extend ClassMethods
klass.instance_eval do
type :string, &:to_s
type :integer, &:to_i
type :float, &:to_f
type :boolean do |value|
if value.is_a?(TrueClass) || value.is_a?(FalseClass)
return value
elsif value.is_a?(String)
return value.presence == ("true" || "1")
elsif value.is_a?(Integer)
return value == 1
else
nil
end
end
end
end
def attributes=(attributes)
@attributes = attributes.with_indifferent_access
end
def attributes
@attributes ||= HashWithIndifferentAccess.new
end
def read_attribute(attr)
caster = self.class.fields[attr.to_sym]
caster.call attributes[attr]
end
def write_attribute(attr, value)
caster = self.class.fields[attr.to_sym]
attributes[attr] = caster.call(value)
end
module ClassMethods
def types
@types ||= {}
end
def type(type_name, &caster)
types[type_name] = caster
end
def fields
@fields ||= {}
end
def field(name, type)
fields[name] = types[type]
define_method "#{name}=" do |value|
write_attribute(name, value)
end
define_method name do
read_attribute(name)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment