Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proc as defaults #41

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/rails-settings/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
15 changes: 14 additions & 1 deletion lib/rails-settings/setting_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions spec/setting_object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 10 additions & 0 deletions spec/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
19 changes: 19 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand Down