diff --git a/README.md b/README.md index 5429acb7..0e308d77 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,25 @@ User.without_settings_for(:calendar) ``` +### Defaults as Proc +```ruby +class User < ActiveRecord::Base + has_settings :calendar, :defaults => Proc.new{ |target| target.company.settings(:calendar)._all } +end + +class Company < ActiveRecord::Base + has_settings :calendar, :defaults => { view: 'week' } +end + +user = User.new +user.settings(:calendar).view +# => 'week' + +user.settings(:calendar)._all +# => { view: 'week' } +``` +Warning! Be carefull with User.default_settings, it contains Proc instead of Hash. + ## Requirements * Ruby 1.9.3 or 2.0.0 diff --git a/lib/rails-settings/configuration.rb b/lib/rails-settings/configuration.rb index 7a275e92..19d441d5 100644 --- a/lib/rails-settings/configuration.rb +++ b/lib/rails-settings/configuration.rb @@ -26,7 +26,7 @@ def initialize(*args, &block) def key(name, options={}) raise ArgumentError.new("has_settings: Symbol expected, but got a #{name.class}") unless name.is_a?(Symbol) raise ArgumentError.new("has_settings: Option :defaults expected, but got #{options.keys.join(', ')}") unless options.blank? || (options.keys == [:defaults]) - @klass.default_settings[name] = (options[:defaults] || {}).stringify_keys.freeze + @klass.default_settings[name] = options[:defaults].is_a?(Proc) ? options[:defaults] : (options[:defaults] || {}).stringify_keys.freeze end end end diff --git a/lib/rails-settings/setting_object.rb b/lib/rails-settings/setting_object.rb index 6b8b2e1a..223ee777 100644 --- a/lib/rails-settings/setting_object.rb +++ b/lib/rails-settings/setting_object.rb @@ -42,6 +42,10 @@ def method_missing(method_name, *args, &block) end end + def _all + (_get_defaults || {}).merge(value) + end + protected if ActiveRecord::VERSION::MAJOR < 4 # Simulate attr_protected by removing all regular attributes @@ -53,7 +57,7 @@ def sanitize_for_mass_assignment(attributes, role = nil) private def _get_value(name) if value[name].nil? - _target_class.default_settings[var.to_sym][name] + _get_defaults[name] else value[name] end @@ -75,6 +79,15 @@ def _target_class target_type.constantize end + def _get_defaults + # Cache result if defaults is a Proc + if _target_class.default_settings[var.to_sym].is_a?(Proc) + _target_class.default_settings[var.to_sym].call(target) + else + _target_class.default_settings[var.to_sym] + end + end + # Patch ActiveRecord to save serialized attributes only if they are changed if ActiveRecord::VERSION::MAJOR < 4 # https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L70 diff --git a/spec/setting_object_spec.rb b/spec/setting_object_spec.rb index 4e717017..112dca6f 100644 --- a/spec/setting_object_spec.rb +++ b/spec/setting_object_spec.rb @@ -94,6 +94,10 @@ saved_setting_object.theme = nil saved_setting_object.value.should == { 'filter' => false } end + + it "should return all possible values" do + saved_setting_object._all.should eq({ 'theme' => 'pink', 'filter' => false, 'view' => 'monthly'}) + end end end diff --git a/spec/settings_spec.rb b/spec/settings_spec.rb index 0e21b292..2b9d450b 100644 --- a/spec/settings_spec.rb +++ b/spec/settings_spec.rb @@ -204,3 +204,13 @@ project.settings(:info).should be_valid end end + +describe "CompanyUser with Proc as defaults" do + let(:company) { Company.create! :name => 'Rails Inc' } + let(:company_user) { CompanyUser.create! :name => 'John', :company_id => company.id } + + it "should have default settings as Company" do + company_user.settings(:calendar).view.should eq(company.settings(:calendar).view) + end + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3760c127..eea3afdb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -52,6 +52,14 @@ class ProjectSettingObject < RailsSettings::SettingObject end end +class CompanyUser < ActiveRecord::Base + has_settings :calendar, :defaults => Proc.new{ |target| target.company.settings(:calendar)._all } +end + +class Company < ActiveRecord::Base + has_settings :calendar, :defaults => { view: 'week' } +end + def setup_db ActiveRecord::Base.configurations = YAML.load_file(File.dirname(__FILE__) + '/database.yml') db_name = ENV['DB'] || 'sqlite' @@ -86,10 +94,21 @@ def setup_db create_table :projects do |t| t.string :name end + + create_table :company_users do |t| + t.string :name + t.references :company, :null => false + end + + create_table :companies do |t| + t.string :name + end end end def clear_db + Company.delete_all + CompanyUser.delete_all User.delete_all Account.delete_all RailsSettings::SettingObject.delete_all