class AssignableValues::ActiveRecord::Restriction::Base
Constants
- SUPPORTED_OPTIONS
Attributes
default[R]
model[R]
options[R]
property[R]
secondary_default[R]
values[R]
Public Class Methods
new(model, property, options, &values)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 20 def initialize(model, property, options, &values) @model = model @property = property @options = options @values = values validate_supported_options! ensure_values_given setup_default define_assignable_values_method setup_validation end
Public Instance Methods
assignable_values(record, options = {})
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 63 def assignable_values(record, options = {}) additional_assignable_values = [] current_values = assignable_values_from_record_or_delegate(record) if options.fetch(:include_old_value, true) && has_previously_saved_value?(record) old_value = previously_saved_value(record) if @options[:multiple] if old_value.is_a?(Array) additional_assignable_values = old_value end elsif !old_value.blank? && !current_values.include?(old_value) additional_assignable_values << old_value end end if options[:decorate] current_values = decorate_values(current_values, record.class) additional_assignable_values = decorate_values(additional_assignable_values, record.class) end if additional_assignable_values.present? # will not keep current_values scoped additional_assignable_values | current_values else current_values end end
set_default(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 45 def set_default(record) if record.new_record? && record.send(property).nil? default_value = evaluate_default(record, default) begin if secondary_default? && !assignable_value?(record, default_value) secondary_default_value = evaluate_default(record, secondary_default) if assignable_value?(record, secondary_default_value) default_value = secondary_default_value end end rescue AssignableValues::DelegateUnavailable # skip secondary defaults if querying assignable values from a nil delegate end record.send("#{property}=", default_value) end true end
validate_record(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 32 def validate_record(record) value = current_value(record) unless allow_blank?(record) && value.blank? begin unless assignable_value?(record, value) record.errors.add(error_property, not_included_error_message) end rescue DelegateUnavailable # if the delegate is unavailable, the validation is skipped end end end
Private Instance Methods
active_record_2?()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 223 def active_record_2? ::ActiveRecord::VERSION::MAJOR < 3 end
allow_blank?(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 178 def allow_blank?(record) evaluate_option(record, @options[:allow_blank]) end
assignable_multi_value?(record, value)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 133 def assignable_multi_value?(record, value) (has_previously_saved_value?(record) && value == previously_saved_value(record)) || (value.blank? ? allow_blank?(record) : subset?(value, assignable_values(record))) end
assignable_single_value?(record, value)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 113 def assignable_single_value?(record, value) (has_previously_saved_value?(record) && value == previously_saved_value(record)) || (value.blank? && allow_blank?(record)) || included_in_assignable_values?(record, value) end
assignable_value?(record, value)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 105 def assignable_value?(record, value) if @options[:multiple] assignable_multi_value?(record, value) else assignable_single_value?(record, value) end end
assignable_values_from_delegate(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 278 def assignable_values_from_delegate(record) delegate = delegate(record) delegate.present? or raise DelegateUnavailable, "Cannot query a nil delegate for assignable values" delegate_query_method = :"assignable_#{model.name.underscore.gsub('/', '_')}_#{property.to_s.pluralize}" args = delegate.method(delegate_query_method).arity == 0 ? [] : [record] delegate.send(delegate_query_method, *args) end
assignable_values_from_record_or_delegate(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 251 def assignable_values_from_record_or_delegate(record) assignable_values = if delegate? assignable_values_from_delegate(record) else record.instance_exec(&@values) end if is_scope?(assignable_values) assignable_values else Array(assignable_values) end end
current_value(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 150 def current_value(record) record.send(property) end
decorate_values(values, _klass)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 162 def decorate_values(values, _klass) values end
default?()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 170 def default? @options.has_key?(:default) end
define_assignable_values_method()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 238 def define_assignable_values_method restriction = self enhance_model do assignable_values_method = :"assignable_#{restriction.property.to_s.pluralize}" define_method assignable_values_method do |*args| # Ruby 1.8.7 does not support optional block arguments :( options = args.first || {} options.merge!({:decorate => true}) restriction.assignable_values(self, options) end end end
delegate(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 265 def delegate(record) evaluate_option(record, delegate_definition) end
delegate?()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 166 def delegate? @options.has_key?(:through) end
delegate_definition()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 182 def delegate_definition options[:through] end
enhance_model(&block)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 190 def enhance_model(&block) @model.class_eval(&block) end
enhance_model_singleton(&block)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 186 def enhance_model_singleton(&block) @model.singleton_class.class_eval(&block) end
ensure_after_initialize_callback_enabled()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 212 def ensure_after_initialize_callback_enabled if active_record_2? enhance_model do # Old ActiveRecord version only call after_initialize callbacks only if this method is defined in a class. unless method_defined?(:after_initialize) define_method(:after_initialize) {} end end end end
ensure_values_given()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 286 def ensure_values_given @values or @options[:through] or raise NoValuesGiven, 'You must supply the list of assignable values by either a block or :through option' end
error_property()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 93 def error_property property end
evaluate_default(record, value_or_proc)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 142 def evaluate_default(record, value_or_proc) if value_or_proc.is_a?(Proc) record.instance_exec(&value_or_proc) else value_or_proc end end
evaluate_option(record, option)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 269 def evaluate_option(record, option) case option when NilClass, TrueClass, FalseClass then option when Symbol then record.send(option) when Proc then record.instance_exec(&option) else raise "Illegal option type: #{option.inspect}" end end
has_previously_saved_value?(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 154 def has_previously_saved_value?(record) raise NotImplementedError end
included_in_assignable_values?(record, value)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 119 def included_in_assignable_values?(record, value) values_or_scope = assignable_values(record, :include_old_value => false) if is_scope?(values_or_scope) values_or_scope.exists?(value.id) unless value.nil? else values_or_scope.include?(value) end end
is_scope?(object)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 129 def is_scope?(object) object.respond_to?(:scoped) || object.respond_to?(:all) end
not_included_error_message()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 97 def not_included_error_message if @options[:message] @options[:message] else I18n.t('errors.messages.inclusion', :default => 'is not included in the list') end end
previously_saved_value(record)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 158 def previously_saved_value(record) raise NotImplementedError end
secondary_default?()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 174 def secondary_default? @options.has_key?(:secondary_default) end
setup_default()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 194 def setup_default if default? @default = options[:default] # for attr_reader @secondary_default = options[:secondary_default] # for attr_reader ensure_after_initialize_callback_enabled restriction = self enhance_model do set_default_method = :"set_default_#{restriction.property}" define_method set_default_method do restriction.set_default(self) end after_initialize set_default_method end elsif secondary_default? raise AssignableValues::NoDefault, "cannot use the :secondary_default option without a :default option" end end
setup_validation()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 227 def setup_validation restriction = self enhance_model do validate_method = :"validate_#{restriction.property}_assignable" define_method validate_method do restriction.validate_record(self) end validate validate_method.to_sym end end
subset?(array1, array2)
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 138 def subset?(array1, array2) array1.is_a?(Array) && array2.is_a?(Array) && (array1 - array2).empty? end
validate_supported_options!()
click to toggle source
# File lib/assignable_values/active_record/restriction/base.rb, line 290 def validate_supported_options! unsupported_options = @options.keys - SUPPORTED_OPTIONS if unsupported_options.any? raise UnsupportedOption, "The following options are not supported: #{unsupported_options.map { |o| ":#{o}" }.join(', ')}" end end