brainstem 0.2.6.1 → 1.0.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/CHANGELOG.md +16 -2
- data/Gemfile.lock +51 -36
- data/README.md +531 -110
- data/brainstem.gemspec +6 -2
- data/lib/brainstem.rb +25 -9
- data/lib/brainstem/concerns/controller_param_management.rb +22 -0
- data/lib/brainstem/concerns/error_presentation.rb +58 -0
- data/lib/brainstem/concerns/inheritable_configuration.rb +29 -0
- data/lib/brainstem/concerns/lookup.rb +30 -0
- data/lib/brainstem/concerns/presenter_dsl.rb +111 -0
- data/lib/brainstem/controller_methods.rb +17 -8
- data/lib/brainstem/dsl/association.rb +55 -0
- data/lib/brainstem/dsl/associations_block.rb +12 -0
- data/lib/brainstem/dsl/base_block.rb +31 -0
- data/lib/brainstem/dsl/conditional.rb +25 -0
- data/lib/brainstem/dsl/conditionals_block.rb +15 -0
- data/lib/brainstem/dsl/configuration.rb +112 -0
- data/lib/brainstem/dsl/field.rb +68 -0
- data/lib/brainstem/dsl/fields_block.rb +25 -0
- data/lib/brainstem/preloader.rb +98 -0
- data/lib/brainstem/presenter.rb +325 -134
- data/lib/brainstem/presenter_collection.rb +82 -286
- data/lib/brainstem/presenter_validator.rb +96 -0
- data/lib/brainstem/query_strategies/README.md +107 -0
- data/lib/brainstem/query_strategies/base_strategy.rb +62 -0
- data/lib/brainstem/query_strategies/filter_and_search.rb +50 -0
- data/lib/brainstem/query_strategies/filter_or_search.rb +103 -0
- data/lib/brainstem/test_helpers.rb +5 -1
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/concerns/controller_param_management_spec.rb +42 -0
- data/spec/brainstem/concerns/error_presentation_spec.rb +113 -0
- data/spec/brainstem/concerns/inheritable_configuration_spec.rb +210 -0
- data/spec/brainstem/concerns/presenter_dsl_spec.rb +412 -0
- data/spec/brainstem/controller_methods_spec.rb +15 -27
- data/spec/brainstem/dsl/association_spec.rb +123 -0
- data/spec/brainstem/dsl/conditional_spec.rb +93 -0
- data/spec/brainstem/dsl/configuration_spec.rb +1 -0
- data/spec/brainstem/dsl/field_spec.rb +212 -0
- data/spec/brainstem/preloader_spec.rb +137 -0
- data/spec/brainstem/presenter_collection_spec.rb +565 -244
- data/spec/brainstem/presenter_spec.rb +726 -167
- data/spec/brainstem/presenter_validator_spec.rb +209 -0
- data/spec/brainstem/query_strategies/filter_and_search_spec.rb +46 -0
- data/spec/brainstem/query_strategies/filter_or_search_spec.rb +45 -0
- data/spec/spec_helper.rb +11 -3
- data/spec/spec_helpers/db.rb +32 -65
- data/spec/spec_helpers/presenters.rb +124 -29
- data/spec/spec_helpers/rr.rb +11 -0
- data/spec/spec_helpers/schema.rb +115 -0
- metadata +126 -30
- data/lib/brainstem/association_field.rb +0 -53
- data/lib/brainstem/engine.rb +0 -4
- data/pkg/brainstem-0.2.5.gem +0 -0
- data/pkg/brainstem-0.2.6.gem +0 -0
- data/spec/spec_helpers/cleanup.rb +0 -23
data/brainstem.gemspec
CHANGED
@@ -17,12 +17,16 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
gem.version = Brainstem::VERSION
|
19
19
|
|
20
|
-
gem.add_dependency "activerecord", ">=
|
20
|
+
gem.add_dependency "activerecord", ">= 4.1"
|
21
|
+
gem.add_dependency "activesupport", ">= 4.1"
|
21
22
|
|
22
23
|
gem.add_development_dependency "rake"
|
23
24
|
gem.add_development_dependency "redcarpet" # for markdown in yard
|
24
25
|
gem.add_development_dependency "rr"
|
25
|
-
gem.add_development_dependency "rspec"
|
26
|
+
gem.add_development_dependency "rspec", "~> 3.5"
|
26
27
|
gem.add_development_dependency "sqlite3"
|
28
|
+
gem.add_development_dependency "database_cleaner"
|
27
29
|
gem.add_development_dependency "yard"
|
30
|
+
gem.add_development_dependency "pry"
|
31
|
+
gem.add_development_dependency "pry-nav"
|
28
32
|
end
|
data/lib/brainstem.rb
CHANGED
@@ -2,6 +2,9 @@ require "brainstem/version"
|
|
2
2
|
require "brainstem/presenter"
|
3
3
|
require "brainstem/presenter_collection"
|
4
4
|
require "brainstem/controller_methods"
|
5
|
+
require "brainstem/query_strategies/base_strategy"
|
6
|
+
require "brainstem/query_strategies/filter_and_search"
|
7
|
+
require "brainstem/query_strategies/filter_or_search"
|
5
8
|
|
6
9
|
# The Brainstem module itself contains a +default_namespace+ class attribute and a few helpers that make managing +PresenterCollections+ and their corresponding namespaces easier.
|
7
10
|
module Brainstem
|
@@ -26,18 +29,13 @@ module Brainstem
|
|
26
29
|
@presenter_collection[namespace.to_s.downcase] ||= PresenterCollection.new
|
27
30
|
end
|
28
31
|
|
32
|
+
# TODO: pull these into the presenter
|
33
|
+
|
29
34
|
# Helper method to quickly add presenter classes that are in a namespace. For example, +add_presenter_class(Api::V1::UserPresenter, "User")+ would add +UserPresenter+ to the PresenterCollection for the +:v1+ namespace as the presenter for the +User+ class.
|
30
35
|
# @param [Brainstem::Presenter] presenter_class The presenter class that is being registered.
|
31
36
|
# @param [Array<String, Class>] klasses Classes that will be presented by the given presenter.
|
32
|
-
def self.add_presenter_class(presenter_class, *klasses)
|
33
|
-
presenter_collection(
|
34
|
-
end
|
35
|
-
|
36
|
-
# @param [Class] klass The Ruby class whose namespace we would like to know.
|
37
|
-
# @return [String] The name of the module containing the passed-in class.
|
38
|
-
def self.namespace_of(klass)
|
39
|
-
names = klass.to_s.split("::")
|
40
|
-
names[-2] ? names[-2] : default_namespace
|
37
|
+
def self.add_presenter_class(presenter_class, namespace, *klasses)
|
38
|
+
presenter_collection(namespace).add_presenter_class(presenter_class, *klasses)
|
41
39
|
end
|
42
40
|
|
43
41
|
# @return [Logger] The Brainstem logger. If Rails is loaded, defaults to the Rails logger. If Rails is not loaded, defaults to a STDOUT logger.
|
@@ -58,4 +56,22 @@ module Brainstem
|
|
58
56
|
def self.logger=(logger)
|
59
57
|
@logger = logger
|
60
58
|
end
|
59
|
+
|
60
|
+
# Reset all PresenterCollection's Presenters, clear the known collections, and reset the default namespace.
|
61
|
+
# This is mostly intended for resetting between tests.
|
62
|
+
def self.reset!
|
63
|
+
if @presenter_collection
|
64
|
+
@presenter_collection.each do |namespace, collection|
|
65
|
+
collection.presenters.each do |klass, presenter|
|
66
|
+
presenter.reset! if presenter.respond_to?(:reset!)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Brainstem::Presenter.reset!
|
72
|
+
Brainstem::Presenter.reset_configuration!
|
73
|
+
|
74
|
+
@presenter_collection = {}
|
75
|
+
@default_namespace = nil
|
76
|
+
end
|
61
77
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Provide `brainstem_model_name` and `brainstem_plural_model_name` in controllers for use when accessing the `params` hash.
|
2
|
+
|
3
|
+
module Brainstem
|
4
|
+
module Concerns
|
5
|
+
module ControllerParamManagement
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :brainstem_plural_model_name, :brainstem_model_name,
|
10
|
+
instance_accessor: false, instance_reader: false, instance_writer: false
|
11
|
+
end
|
12
|
+
|
13
|
+
def brainstem_model_name
|
14
|
+
self.class.brainstem_model_name.to_s.presence || controller_name.singularize
|
15
|
+
end
|
16
|
+
|
17
|
+
def brainstem_plural_model_name
|
18
|
+
self.class.brainstem_plural_model_name.to_s.presence || brainstem_model_name.pluralize
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Brainstem
|
2
|
+
module Concerns
|
3
|
+
module ErrorPresentation
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
# Given one or more error messages, return Brainstem-style errors, defaulting to type 'system'.
|
7
|
+
def brainstem_system_error(*messages)
|
8
|
+
options = messages.last.is_a?(Hash) ? messages.pop : {}
|
9
|
+
response = { :errors => [] }
|
10
|
+
messages.flatten.uniq.each do |message|
|
11
|
+
response[:errors] << {
|
12
|
+
:type => options[:type] || :system,
|
13
|
+
:message => message
|
14
|
+
}
|
15
|
+
end
|
16
|
+
response
|
17
|
+
end
|
18
|
+
|
19
|
+
# Given a model or models, outputs Brainstem-style errors, for example:
|
20
|
+
# { :errors => [{ :type => 'validation', :field => :thing_id, :message => "Thing is required" }] }
|
21
|
+
# If given a rewrite_params hash, it will convert from an internal column name to an external name.
|
22
|
+
# Note: you must validate models prior to passing them into this method. It does not call `valid?` on them.
|
23
|
+
def brainstem_model_error(object_or_objects, options = {})
|
24
|
+
json = { :errors => [] }
|
25
|
+
|
26
|
+
[object_or_objects].flatten.each.with_index do |object, index|
|
27
|
+
case object
|
28
|
+
when Hash
|
29
|
+
attribute = object[:field] || :base
|
30
|
+
json[:errors] << {
|
31
|
+
:type => object[:type] || 'validation',
|
32
|
+
:field => (options[:rewrite_params] || {}).reverse_merge(attribute => attribute).invert[attribute],
|
33
|
+
:message => object[:message] || raise(ArgumentError, "message required")
|
34
|
+
}
|
35
|
+
when String
|
36
|
+
json[:errors] << { :type => 'validation', :field => :base, :message => object }
|
37
|
+
else
|
38
|
+
object.errors.each do |attribute, attribute_error|
|
39
|
+
json[:errors] << {
|
40
|
+
:type => 'validation',
|
41
|
+
:field => (options[:rewrite_params] || {}).reverse_merge(attribute => attribute).invert[attribute],
|
42
|
+
:message => brainstem_full_error_message(object, attribute, attribute_error),
|
43
|
+
:index => index
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
json
|
49
|
+
end
|
50
|
+
|
51
|
+
# Helper to convert an attribute name (e.g., "thing_id") and error (e.g., "is invalid") into a combined full message.
|
52
|
+
# Also handles traditional "^You messed up"-style errors that should not be combined with humanized attribute names.
|
53
|
+
def brainstem_full_error_message(object, attribute, text)
|
54
|
+
text[0] == "^" ? text[1..-1] : object.errors.full_message(attribute, text)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'brainstem/dsl/configuration'
|
2
|
+
|
3
|
+
module Brainstem
|
4
|
+
module Concerns
|
5
|
+
module InheritableConfiguration
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def configuration
|
10
|
+
@configuration ||= begin
|
11
|
+
if superclass.respond_to?(:configuration)
|
12
|
+
DSL::Configuration.new(superclass.configuration)
|
13
|
+
else
|
14
|
+
DSL::Configuration.new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear_configuration!
|
20
|
+
@configuration = nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def configuration
|
25
|
+
self.class.configuration
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Brainstem
|
2
|
+
module Concerns
|
3
|
+
module Lookup
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def run_on_with_lookup(model, context, helper_instance)
|
7
|
+
context[:lookup][key_for_lookup][name] ||= begin
|
8
|
+
proc = options[:lookup]
|
9
|
+
lookup = helper_instance.instance_exec(context[:models], &proc)
|
10
|
+
if !options[:lookup_fetch].present? && !lookup.respond_to?(:[])
|
11
|
+
raise(StandardError, 'Brainstem expects the return result of the `lookup` to be a Hash since it must respond to [] in order to access the model\'s assocation(s). Default: lookup_fetch: lambda { |lookup, model| lookup[model.id] }`')
|
12
|
+
end
|
13
|
+
|
14
|
+
lookup
|
15
|
+
end
|
16
|
+
|
17
|
+
if options[:lookup_fetch]
|
18
|
+
proc = options[:lookup_fetch]
|
19
|
+
helper_instance.instance_exec(context[:lookup][key_for_lookup][name], model, &proc)
|
20
|
+
else
|
21
|
+
context[:lookup][key_for_lookup][name][model.id]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def key_for_lookup
|
26
|
+
raise(StandardError 'Implement `key_for_lookup` when including Lookup Module.')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'brainstem/concerns/inheritable_configuration'
|
2
|
+
require 'brainstem/dsl/association'
|
3
|
+
require 'brainstem/dsl/field'
|
4
|
+
require 'brainstem/dsl/conditional'
|
5
|
+
|
6
|
+
require 'brainstem/dsl/base_block'
|
7
|
+
require 'brainstem/dsl/conditionals_block'
|
8
|
+
require 'brainstem/dsl/fields_block'
|
9
|
+
require 'brainstem/dsl/associations_block'
|
10
|
+
|
11
|
+
|
12
|
+
module Brainstem
|
13
|
+
module Concerns
|
14
|
+
module PresenterDSL
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
include Brainstem::Concerns::InheritableConfiguration
|
17
|
+
|
18
|
+
included do
|
19
|
+
reset_configuration!
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def preload(*args)
|
24
|
+
configuration.array!(:preloads).concat args
|
25
|
+
end
|
26
|
+
|
27
|
+
def conditionals(&block)
|
28
|
+
ConditionalsBlock.new(configuration, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def fields(&block)
|
32
|
+
FieldsBlock.new(configuration[:fields], &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def associations(&block)
|
36
|
+
AssociationsBlock.new(configuration, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Declare a helper module or block whose methods will be available in dynamic fields and associations.
|
40
|
+
def helper(mod = nil, &block)
|
41
|
+
if mod
|
42
|
+
configuration[:helpers] << mod
|
43
|
+
end
|
44
|
+
|
45
|
+
if block
|
46
|
+
configuration[:helpers] << Module.new.tap { |mod| mod.module_eval(&block) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @overload default_sort_order(sort_string)
|
51
|
+
# Sets a default sort order.
|
52
|
+
# @param [String] sort_string The sort order to apply by default while presenting. The string must contain the name of a sort order that has explicitly been declared using {sort_order}. The string may end in +:asc+ or +:desc+ to indicate the default order's direction.
|
53
|
+
# @return [String] The new default sort order.
|
54
|
+
# @overload default_sort_order
|
55
|
+
# @return [String] The default sort order, or nil if one is not set.
|
56
|
+
def default_sort_order(sort_string = nil)
|
57
|
+
configuration[:default_sort_order] = sort_string if sort_string
|
58
|
+
configuration[:default_sort_order]
|
59
|
+
end
|
60
|
+
|
61
|
+
# @overload sort_order(name, order)
|
62
|
+
# @param [Symbol] name The name of the sort order.
|
63
|
+
# @param [String] order The SQL string to use to sort the presented data.
|
64
|
+
# @overload sort_order(name, &block)
|
65
|
+
# @yieldparam scope [ActiveRecord::Relation] The scope representing the data being presented.
|
66
|
+
# @yieldreturn [ActiveRecord::Relation] A new scope that adds ordering requirements to the scope that was yielded.
|
67
|
+
# Create a named sort order, either containing a string to use as ORDER in a query, or with a block that adds an order Arel predicate to a scope.
|
68
|
+
# @raise [ArgumentError] if neither an order string or block is given.
|
69
|
+
def sort_order(name, order = nil, &block)
|
70
|
+
raise ArgumentError, "A sort order must be given" unless block_given? || order
|
71
|
+
configuration[:sort_orders][name] = (block_given? ? block : order)
|
72
|
+
end
|
73
|
+
|
74
|
+
# @overload filter(name, options = {})
|
75
|
+
# @param [Symbol] name The name of the scope that may be applied as a filter.
|
76
|
+
# @option options [Object] :default If set, causes this filter to be applied to every request. If the filter accepts parameters, the value given here will be passed to the filter when it is applied.
|
77
|
+
# @overload filter(name, options = {}, &block)
|
78
|
+
# @param [Symbol] name The filter can be requested using this name.
|
79
|
+
# @yieldparam scope [ActiveRecord::Relation] The scope that the filter should use as a base.
|
80
|
+
# @yieldparam arg [Object] The argument passed when the filter was requested.
|
81
|
+
# @yieldreturn [ActiveRecord::Relation] A new scope that filters the scope that was yielded.
|
82
|
+
def filter(name, options = {}, &block)
|
83
|
+
configuration[:filters][name] = [options, (block_given? ? block : nil)]
|
84
|
+
end
|
85
|
+
|
86
|
+
def search(&block)
|
87
|
+
configuration[:search] = block
|
88
|
+
end
|
89
|
+
|
90
|
+
def brainstem_key(key)
|
91
|
+
configuration[:brainstem_key] = key.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def query_strategy(strategy)
|
95
|
+
configuration[:query_strategy] = strategy
|
96
|
+
end
|
97
|
+
|
98
|
+
# @api private
|
99
|
+
def reset_configuration!
|
100
|
+
configuration.array!(:preloads)
|
101
|
+
configuration.array!(:helpers)
|
102
|
+
configuration.nest!(:conditionals)
|
103
|
+
configuration.nest!(:fields)
|
104
|
+
configuration.nest!(:filters)
|
105
|
+
configuration.nest!(:sort_orders)
|
106
|
+
configuration.nest!(:associations)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -1,32 +1,38 @@
|
|
1
|
+
require 'brainstem/concerns/controller_param_management'
|
2
|
+
require 'brainstem/concerns/error_presentation'
|
3
|
+
|
1
4
|
module Brainstem
|
2
5
|
|
3
6
|
# ControllerMethods are intended to be included into controllers that will be handling requests for presented objects.
|
4
7
|
# The present method will pass through +params+, so that any allowed and requested includes, filters, sort orders
|
5
8
|
# will be applied to the presented data.
|
6
9
|
module ControllerMethods
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
include Concerns::ControllerParamManagement
|
12
|
+
include Concerns::ErrorPresentation
|
7
13
|
|
8
14
|
# Return a Ruby hash that contains models requested by the user's params and allowed
|
9
15
|
# by the +name+ presenter's configuration.
|
10
16
|
#
|
11
17
|
# Pass the returned hash to the render method to convert it into a useful format.
|
12
18
|
# For example:
|
13
|
-
# render :json =>
|
19
|
+
# render :json => brainstem_present("post"){ Post.where(:draft => false) }
|
14
20
|
# @param (see PresenterCollection#presenting)
|
15
21
|
# @option options [String] :namespace ("none") the namespace to be presented from
|
16
22
|
# @yield (see PresenterCollection#presenting)
|
17
23
|
# @return (see PresenterCollection#presenting)
|
18
|
-
def
|
24
|
+
def brainstem_present(name, options = {}, &block)
|
19
25
|
Brainstem.presenter_collection(options[:namespace]).presenting(name, options.reverse_merge(:params => params), &block)
|
20
26
|
end
|
21
27
|
|
22
|
-
# Similar to ControllerMethods#
|
23
|
-
# filters.
|
28
|
+
# Similar to ControllerMethods#brainstem_present, but always returns all of the given objects, not just those that
|
29
|
+
# match any provided filters.
|
24
30
|
# @option options [String] :namespace ("none") the namespace to be presented from
|
25
31
|
# @option options [Hash] :key_map a Hash from Class name to json key name, if desired.
|
26
32
|
# e.g., map 'SystemWidgets' objects to the 'widgets' key in the JSON. This is
|
27
33
|
# only required if the name cannot be inferred.
|
28
34
|
# @return (see PresenterCollection#presenting)
|
29
|
-
def
|
35
|
+
def brainstem_present_object(objects, options = {})
|
30
36
|
options.merge!(:params => params, :apply_default_filters => false)
|
31
37
|
|
32
38
|
if objects.is_a?(ActiveRecord::Relation) || objects.is_a?(Array)
|
@@ -39,9 +45,12 @@ module Brainstem
|
|
39
45
|
options[:params][:only] = ids.to_s
|
40
46
|
end
|
41
47
|
|
42
|
-
|
43
|
-
|
48
|
+
if options[:key_map]
|
49
|
+
raise "brainstem_present_object no longer accepts a :key_map. Use brainstem_key annotations on your presenters instead."
|
50
|
+
end
|
51
|
+
|
52
|
+
brainstem_present(klass, options) { klass.where(:id => ids) }
|
44
53
|
end
|
45
|
-
alias_method :
|
54
|
+
alias_method :brainstem_present_objects, :brainstem_present_object
|
46
55
|
end
|
47
56
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'brainstem/concerns/lookup'
|
2
|
+
|
3
|
+
module Brainstem
|
4
|
+
module DSL
|
5
|
+
class Association
|
6
|
+
include Brainstem::Concerns::Lookup
|
7
|
+
|
8
|
+
attr_reader :name, :target_class, :description, :options
|
9
|
+
|
10
|
+
def initialize(name, target_class, description, options)
|
11
|
+
@name = name.to_s
|
12
|
+
@target_class = target_class
|
13
|
+
@description = description
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_name
|
18
|
+
if options[:dynamic] || options[:lookup]
|
19
|
+
nil
|
20
|
+
else
|
21
|
+
(options[:via].presence || name).to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_on(model, context, helper_instance = Object.new)
|
26
|
+
if options[:lookup]
|
27
|
+
run_on_with_lookup(model, context, helper_instance)
|
28
|
+
elsif options[:dynamic]
|
29
|
+
proc = options[:dynamic]
|
30
|
+
if proc.arity == 1
|
31
|
+
helper_instance.instance_exec(model, &proc)
|
32
|
+
else
|
33
|
+
helper_instance.instance_exec(&proc)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
model.send(method_name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def polymorphic?
|
41
|
+
target_class == :polymorphic
|
42
|
+
end
|
43
|
+
|
44
|
+
def always_return_ref_with_sti_base?
|
45
|
+
options[:always_return_ref_with_sti_base]
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def key_for_lookup
|
51
|
+
:associations
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|