Last active
August 29, 2015 14:28
-
-
Save seanlinsley/c606069560120ec8e4d2 to your computer and use it in GitHub Desktop.
Inheritable settings between two models, in Rails
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Child < ActiveRecord::Base | |
| belongs_to :parent | |
| INHERITABLE_SETTINGS = %i[foo bar baz] | |
| INHERITABLE_SETTINGS.each do |attr| | |
| define_method attr do | |
| value = read_attribute(attr) | |
| default = default_setting(attr) | |
| inherited = inherited_setting(attr) | |
| inherited && value == default ? inherited : value | |
| end | |
| # This is a total hack. It won't respond to `includes` or `joins` correctly. | |
| # If we want better support, we'll have to monkeypatch `add_constraints` in Rails 4.1 | |
| # or `last_chain_scope` in >= 4.2 on ActiveRecord::Associations::AssociationScope. | |
| if /(?<association>.+)_id/ =~ attr | |
| define_method association do | |
| assoc = association(association) | |
| assoc.association_scope.bind_values = [[ | |
| assoc.klass.columns_hash['id'], public_send(attr) | |
| ]] | |
| assoc.load_target | |
| end | |
| end | |
| end | |
| def inherited_setting(attr) | |
| return unless parent | |
| parent.settings[attr.to_s] | |
| end | |
| def default_setting(attr) | |
| self.class.column_defaults[attr.to_s] | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Allows the child's attributes to be read and written by a regular form. | |
| class Parent < ActiveRecord::Base | |
| Child::INHERITABLE_SETTINGS.each do |attr| | |
| define_method attr do | |
| settings[attr.to_s] | |
| end | |
| define_method "#{attr}=" do |value| | |
| settings_will_change! | |
| if [nil, ''].include? value | |
| settings.delete attr.to_s | |
| else | |
| settings[attr.to_s] = cast_property_value(attr, value) | |
| end | |
| end | |
| end | |
| def cast_child_value(attr, value) | |
| case Child.columns_hash[attr.to_s].type | |
| when :boolean | |
| ActiveRecord::ConnectionAdapters::Column.value_to_boolean value | |
| when :integer | |
| value.to_i | |
| when :decimal | |
| value.to_f | |
| else | |
| value | |
| end | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # The orignal version would prevent inheritable settings from working with associations. | |
| # Specifically, it's used in `find_target?`, which decides whether to do a database request. | |
| module SupportInhertiableAssociations | |
| def foreign_key_present? | |
| owner.public_send reflection.foreign_key | |
| end | |
| end | |
| ActiveRecord::Associations::BelongsToAssociation.prepend SupportInhertiableAssociations |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment