datastax_rails 1.2.3 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +20 -8
  4. data/config/schema.xml.erb +22 -19
  5. data/config/solrconfig.xml.erb +1 -1
  6. data/lib/cql-rb_extensions.rb +27 -0
  7. data/lib/datastax_rails.rb +13 -17
  8. data/lib/datastax_rails/associations/association.rb +1 -4
  9. data/lib/datastax_rails/associations/collection_proxy.rb +0 -13
  10. data/lib/datastax_rails/attribute_assignment.rb +28 -91
  11. data/lib/datastax_rails/attribute_methods.rb +109 -44
  12. data/lib/datastax_rails/attribute_methods/before_type_cast.rb +71 -0
  13. data/lib/datastax_rails/attribute_methods/dirty.rb +52 -11
  14. data/lib/datastax_rails/attribute_methods/primary_key.rb +87 -0
  15. data/lib/datastax_rails/attribute_methods/read.rb +120 -0
  16. data/lib/datastax_rails/attribute_methods/typecasting.rb +52 -21
  17. data/lib/datastax_rails/attribute_methods/write.rb +59 -0
  18. data/lib/datastax_rails/base.rb +227 -236
  19. data/lib/datastax_rails/cassandra_only_model.rb +25 -19
  20. data/lib/datastax_rails/column.rb +384 -0
  21. data/lib/datastax_rails/connection.rb +12 -13
  22. data/lib/datastax_rails/cql/alter_column_family.rb +0 -1
  23. data/lib/datastax_rails/cql/base.rb +15 -3
  24. data/lib/datastax_rails/cql/column_family.rb +2 -2
  25. data/lib/datastax_rails/cql/create_column_family.rb +7 -18
  26. data/lib/datastax_rails/cql/delete.rb +4 -9
  27. data/lib/datastax_rails/cql/insert.rb +2 -8
  28. data/lib/datastax_rails/cql/select.rb +4 -4
  29. data/lib/datastax_rails/cql/update.rb +8 -17
  30. data/lib/datastax_rails/dynamic_model.rb +98 -0
  31. data/lib/datastax_rails/payload_model.rb +19 -31
  32. data/lib/datastax_rails/persistence.rb +39 -54
  33. data/lib/datastax_rails/railtie.rb +1 -0
  34. data/lib/datastax_rails/reflection.rb +1 -1
  35. data/lib/datastax_rails/relation.rb +20 -20
  36. data/lib/datastax_rails/relation/batches.rb +18 -16
  37. data/lib/datastax_rails/relation/facet_methods.rb +1 -1
  38. data/lib/datastax_rails/relation/finder_methods.rb +6 -10
  39. data/lib/datastax_rails/relation/search_methods.rb +62 -48
  40. data/lib/datastax_rails/rsolr_client_wrapper.rb +1 -1
  41. data/lib/datastax_rails/schema/cassandra.rb +34 -62
  42. data/lib/datastax_rails/schema/migrator.rb +9 -24
  43. data/lib/datastax_rails/schema/solr.rb +13 -30
  44. data/lib/datastax_rails/schema_cache.rb +67 -0
  45. data/lib/datastax_rails/timestamps.rb +84 -11
  46. data/lib/datastax_rails/types/dirty_collection.rb +88 -0
  47. data/lib/datastax_rails/types/dynamic_list.rb +14 -0
  48. data/lib/datastax_rails/types/dynamic_map.rb +32 -0
  49. data/lib/datastax_rails/types/dynamic_set.rb +10 -0
  50. data/lib/datastax_rails/util/solr_repair.rb +4 -5
  51. data/lib/datastax_rails/validations.rb +6 -12
  52. data/lib/datastax_rails/validations/uniqueness.rb +0 -4
  53. data/lib/datastax_rails/version.rb +1 -1
  54. data/lib/datastax_rails/wide_storage_model.rb +13 -29
  55. data/lib/schema_migration.rb +4 -0
  56. data/spec/datastax_rails/associations_spec.rb +0 -1
  57. data/spec/datastax_rails/attribute_methods_spec.rb +9 -6
  58. data/spec/datastax_rails/base_spec.rb +26 -0
  59. data/spec/datastax_rails/column_spec.rb +238 -0
  60. data/spec/datastax_rails/cql/select_spec.rb +1 -1
  61. data/spec/datastax_rails/cql/update_spec.rb +2 -2
  62. data/spec/datastax_rails/persistence_spec.rb +29 -15
  63. data/spec/datastax_rails/relation/batches_spec.rb +5 -5
  64. data/spec/datastax_rails/relation/finder_methods_spec.rb +0 -20
  65. data/spec/datastax_rails/relation/search_methods_spec.rb +8 -0
  66. data/spec/datastax_rails/relation_spec.rb +7 -0
  67. data/spec/datastax_rails/schema/migrator_spec.rb +5 -10
  68. data/spec/datastax_rails/schema/solr_spec.rb +1 -1
  69. data/spec/datastax_rails/types/dynamic_list_spec.rb +20 -0
  70. data/spec/datastax_rails/types/dynamic_map_spec.rb +22 -0
  71. data/spec/datastax_rails/types/dynamic_set_spec.rb +16 -0
  72. data/spec/dummy/config/application.rb +2 -1
  73. data/spec/dummy/config/datastax.yml +6 -3
  74. data/spec/dummy/config/environments/development.rb +4 -5
  75. data/spec/dummy/config/environments/test.rb +0 -5
  76. data/spec/dummy/log/development.log +18 -0
  77. data/spec/dummy/log/test.log +36 -0
  78. data/spec/feature/dynamic_fields_spec.rb +9 -0
  79. data/spec/feature/overloaded_tables_spec.rb +24 -0
  80. data/spec/spec_helper.rb +1 -1
  81. data/spec/support/default_consistency_shared_examples.rb +2 -2
  82. data/spec/support/models.rb +28 -14
  83. metadata +212 -188
  84. data/lib/datastax_rails/identity.rb +0 -64
  85. data/lib/datastax_rails/identity/abstract_key_factory.rb +0 -29
  86. data/lib/datastax_rails/identity/custom_key_factory.rb +0 -37
  87. data/lib/datastax_rails/identity/hashed_natural_key_factory.rb +0 -10
  88. data/lib/datastax_rails/identity/natural_key_factory.rb +0 -39
  89. data/lib/datastax_rails/identity/uuid_key_factory.rb +0 -27
  90. data/lib/datastax_rails/type.rb +0 -16
  91. data/lib/datastax_rails/types.rb +0 -9
  92. data/lib/datastax_rails/types/array_type.rb +0 -86
  93. data/lib/datastax_rails/types/base_type.rb +0 -42
  94. data/lib/datastax_rails/types/binary_type.rb +0 -19
  95. data/lib/datastax_rails/types/boolean_type.rb +0 -22
  96. data/lib/datastax_rails/types/date_type.rb +0 -23
  97. data/lib/datastax_rails/types/float_type.rb +0 -18
  98. data/lib/datastax_rails/types/integer_type.rb +0 -18
  99. data/lib/datastax_rails/types/string_type.rb +0 -16
  100. data/lib/datastax_rails/types/text_type.rb +0 -15
  101. data/lib/datastax_rails/types/time_type.rb +0 -23
  102. data/spec/datastax_rails/types/float_type_spec.rb +0 -31
  103. data/spec/datastax_rails/types/integer_type_spec.rb +0 -31
  104. data/spec/datastax_rails/types/time_type_spec.rb +0 -28
@@ -10,46 +10,29 @@ module DatastaxRails
10
10
  @fields = []
11
11
  @copy_fields = []
12
12
  @fulltext_fields = []
13
- @custom_fields = ""
14
- model.attribute_definitions.values.each do |attr|
15
- coder = attr.coder
16
- if coder.options[:solr_type]
17
- @fields.push({ :name => attr.name,
18
- :type => coder.options[:solr_type].to_s,
19
- :indexed => (coder.options[:indexed] == :solr || coder.options[:indexed] == :both).to_s,
20
- :stored => coder.options[:stored].to_s,
21
- :multi_valued => coder.options[:multi_valued].to_s })
22
- end
23
- if coder.options[:sortable] && coder.options[:tokenized]
24
- @fields.push({ :name => "sort_" + attr.name,
25
- :type => "string",
26
- :indexed => true,
27
- :stored => false,
28
- :multi_valued => false })
29
- @copy_fields.push({ :source => attr.name, :dest => "sort_" + attr.name }) if (coder.options[:indexed] || coder.options[:stored])
30
- end
31
- if coder.options[:fulltext]
32
- @fulltext_fields << attr.name if (coder.options[:indexed] || coder.options[:stored])
33
- end
13
+ if model <= WideStorageModel
14
+ @primary_key = "(#{model.primary_key},#{model.cluster_by})"
15
+ else
16
+ @primary_key = model.primary_key
34
17
  end
35
- # Sort the fields so that no matter what order the attributes are arranged into the
36
- # same schema file gets generated
18
+ @custom_fields = ""
19
+ @columns = model.attribute_definitions.values
37
20
  @fields.sort! {|a,b| a[:name] <=> b[:name]}
38
21
  @copy_fields.sort! {|a,b| a[:source] <=> b[:source]}
39
22
  @fulltext_fields.sort!
40
23
 
41
24
  if Rails.root.join('config','solr',"#{model.column_family}-schema.xml.erb").exist?
42
25
  say "Using custom schema for #{model.name}", :subitem
43
- ERB.new(Rails.root.join('config','solr',"#{model.column_family}-schema.xml.erb").read).result(binding)
26
+ ERB.new(Rails.root.join('config','solr',"#{model.column_family}-schema.xml.erb").read, 0, '>').result(binding)
44
27
  else
45
- ERB.new(File.read(File.join(File.dirname(__FILE__),"..","..","..","config","schema.xml.erb"))).result(binding)
28
+ ERB.new(File.read(File.join(File.dirname(__FILE__),"..","..","..","config","schema.xml.erb")), 0, '>').result(binding)
46
29
  end
47
30
  end
48
31
 
49
32
  # Sends a command to Solr instructing it to reindex the data. The data is reindexed in the background,
50
33
  # and the new index is swapped in once it is finished.
51
- def reindex_solr(model)
52
- url = "#{DatastaxRails::Base.solr_base_url}/admin/cores?action=RELOAD&name=#{DatastaxRails::Base.config[:keyspace]}.#{model.column_family}&reindex=true&deleteAll=false"
34
+ def reindex_solr(model, destructive=false)
35
+ url = "#{DatastaxRails::Base.solr_base_url}/admin/cores?action=RELOAD&name=#{DatastaxRails::Base.config[:keyspace]}.#{model.column_family}&reindex=true&deleteAll=#{destructive.to_s}"
53
36
  say "Posting reindex command to '#{url}'", :subitem
54
37
  `curl -s -X POST '#{url}'`
55
38
  say "Reindexing will run in the background", :subitem
@@ -89,11 +72,11 @@ module DatastaxRails
89
72
  stopwords_digest = Digest::SHA1.hexdigest(stopwords)
90
73
  schema_digest = Digest::SHA1.hexdigest(schema)
91
74
 
92
- newcf = !column_family_exists?(model.column_family.to_s)
75
+ newcf = !column_exists?(model.column_family, 'solr_query')
93
76
  force ||= newcf
94
77
 
95
- results = DatastaxRails::Cql::Select.new(SchemaMigration, ['*']).conditions(:key => model.column_family).execute
96
- sm_digests = CassandraCQL::Result.new(results).fetch.try(:to_hash) || {}
78
+ results = DatastaxRails::Cql::Select.new(SchemaMigration, ['*']).conditions(:cf => model.column_family).execute
79
+ sm_digests = results.first || {}
97
80
 
98
81
  solr_url = "#{DatastaxRails::Base.solr_base_url}/resource/#{@keyspace}.#{model.column_family}"
99
82
 
@@ -0,0 +1,67 @@
1
+ module DatastaxRails
2
+ class SchemaCache
3
+ attr_reader :primary_keys, :tables
4
+ attr_reader :connection
5
+
6
+ def initialize(conn)
7
+ @connection = conn
8
+ @tables = {}
9
+
10
+ @columns = Hash.new do |h, table_name|
11
+ h[table_name] = connection.columns(table_name, "#{table_name} Columns")
12
+ end
13
+
14
+ @columns_hash = Hash.new do |h, table_name|
15
+ h[table_name] = Hash[columns[table_name].map { |col|
16
+ [col.name, col]
17
+ }]
18
+ end
19
+
20
+ @primary_keys = Hash.new do |h, table_name|
21
+ h[table_name] = table_exists?(table_name) ? connection.primary_key(table_name) : nil
22
+ end
23
+ end
24
+
25
+ # A cached lookup for table existence.
26
+ def table_exists?(name)
27
+ return @tables[name] if @tables.key? name
28
+
29
+ @tables[name] = connection.table_exists?(name)
30
+ end
31
+
32
+ # Get the columns for a table
33
+ def columns(table = nil)
34
+ if table
35
+ @columns[table]
36
+ else
37
+ @columns
38
+ end
39
+ end
40
+
41
+ # Get the columns for a table as a hash, key is the column name
42
+ # value is the column object.
43
+ def columns_hash(table = nil)
44
+ if table
45
+ @columns_hash[table]
46
+ else
47
+ @columns_hash
48
+ end
49
+ end
50
+
51
+ # Clears out internal caches
52
+ def clear!
53
+ @columns.clear
54
+ @columns_hash.clear
55
+ @primary_keys.clear
56
+ @tables.clear
57
+ end
58
+
59
+ # Clear out internal caches for table with +table_name+.
60
+ def clear_table_cache!(table_name)
61
+ @columns.delete table_name
62
+ @columns_hash.delete table_name
63
+ @primary_keys.delete table_name
64
+ @tables.delete table_name
65
+ end
66
+ end
67
+ end
@@ -1,25 +1,98 @@
1
1
  module DatastaxRails
2
+ # = DatastaxRails Timestamps
3
+ #
4
+ # DatastaxRails automatically timestamps create and update operations if the
5
+ # table has fields named <tt>created_at</tt> or <tt>updated_at</tt>.
6
+ #
7
+ # Timestamping can be turned off by setting:
8
+ #
9
+ # DatastaxRails::Base.record_timestamps = false
2
10
  module Timestamps
3
11
  extend ActiveSupport::Concern
4
12
 
5
13
  included do
6
- # attribute :created_at, :type => :time#_with_zone
7
- # attribute :updated_at, :type => :time#_with_zone
14
+ class_attribute :record_timestamps
15
+ self.record_timestamps = true
16
+ end
8
17
 
9
- before_create do #|r|
10
- if self.respond_to?(:created_at=)
11
- self.created_at ||= Time.current
12
- end
13
- if self.respond_to?(:updated_at=)
14
- self.updated_at ||= Time.current
18
+ def initialize_dup(other) # :nodoc:
19
+ clear_timestamp_attributes
20
+ super
21
+ end
22
+
23
+ private
24
+
25
+ def _create_record(*args)
26
+ if self.record_timestamps
27
+ current_time = current_time_from_proper_timezone
28
+
29
+ all_timestamp_attributes.each do |column|
30
+ if respond_to?(column) && respond_to?("#{column}=") && self.send(column).nil?
31
+ write_attribute(column.to_s, current_time)
32
+ end
15
33
  end
16
34
  end
17
35
 
18
- before_update :if => :changed? do #|r|
19
- if self.respond_to?(:updated_at=)
20
- self.updated_at = Time.current
36
+ super
37
+ end
38
+
39
+ def _update_record(*args)
40
+ if should_record_timestamps?
41
+ current_time = current_time_from_proper_timezone
42
+
43
+ timestamp_attributes_for_update_in_model.each do |column|
44
+ column = column.to_s
45
+ next if attribute_changed?(column)
46
+ write_attribute(column, current_time)
21
47
  end
22
48
  end
49
+ super
50
+ end
51
+
52
+ def should_record_timestamps?
53
+ self.record_timestamps && (changed? || (attributes.keys & self.class.serialized_attributes.keys).present?)
54
+ end
55
+
56
+ def timestamp_attributes_for_create_in_model
57
+ timestamp_attributes_for_create.select { |c| self.class.column_names.include?(c.to_s) }
58
+ end
59
+
60
+ def timestamp_attributes_for_update_in_model
61
+ timestamp_attributes_for_update.select { |c| self.class.column_names.include?(c.to_s) }
62
+ end
63
+
64
+ def all_timestamp_attributes_in_model
65
+ timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model
66
+ end
67
+
68
+ def timestamp_attributes_for_update
69
+ [:updated_at]
70
+ end
71
+
72
+ def timestamp_attributes_for_create
73
+ [:created_at]
74
+ end
75
+
76
+ def all_timestamp_attributes
77
+ timestamp_attributes_for_create + timestamp_attributes_for_update
78
+ end
79
+
80
+ def max_updated_column_timestamp
81
+ if (timestamps = timestamp_attributes_for_update.map { |attr| self[attr] }.compact).present?
82
+ timestamps.map { |ts| ts.to_time }.max
83
+ end
84
+ end
85
+
86
+ def current_time_from_proper_timezone
87
+ self.class.default_timezone == :utc ? Time.now.utc : Time.now
88
+ end
89
+
90
+ # Clear attributes and changed_attributes
91
+ def clear_timestamp_attributes
92
+ all_timestamp_attributes_in_model.each do |attribute_name|
93
+ self[attribute_name] = nil
94
+ changed_attributes.delete(attribute_name)
95
+ end
23
96
  end
24
97
  end
25
98
  end
@@ -0,0 +1,88 @@
1
+ # An extension to normal arrays and hashes that allow for tracking of dirty values. This is
2
+ # used by ActiveModel's change tracking framework.
3
+ module DatastaxRails
4
+ module Types
5
+ module DirtyCollection
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_accessor :record, :name
10
+
11
+ methods = [:<<, :delete, :[]=, :add, :subtract, :store, :push, :pop, :unshift, :shift, :insert, :clear] +
12
+ ActiveSupport::HashWithIndifferentAccess.instance_methods(true).select{|m| m.to_s.ends_with?('!')} +
13
+ Array.instance_methods(true).select{|m| m.to_s.ends_with?('!')} +
14
+ Set.instance_methods(true).select{|m| m.to_s.ends_with?('!')}
15
+
16
+ methods.each do |m|
17
+ if self.instance_methods.include?(m)
18
+ alias_method "___#{m}", m
19
+ original_method = self.instance_method(m)
20
+ define_method(m) do |*args, &block|
21
+ modifying do
22
+ original_method.bind(self).call(*args, &block)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def initialize(record, name, collection)
30
+ @record = record
31
+ @name = name.to_s
32
+
33
+ super(collection)
34
+ organize_collection
35
+ end
36
+
37
+ def delete(obj)
38
+ modifying do
39
+ super
40
+ end
41
+ end
42
+
43
+ def self.ignore_modifications
44
+ original = $dsr_ignore_modifications
45
+ $dsr_ignore_modifications = true
46
+ result = yield
47
+ $dsr_ignore_modifications = original
48
+ result
49
+ end
50
+
51
+ private
52
+ def modifying
53
+ # So there's a problem with overriding the map! method on Array.
54
+ # When we do the update to record.attributes, HashWithIndifferentAccess
55
+ # calls .map! on our Array. This causes infinite recursion which
56
+ # I find is generally not a desired behavior. We use a variable
57
+ # to tell if we've already hijacked the call.
58
+ if $dsr_ignore_modifications
59
+ yield
60
+ else
61
+ DirtyCollection.ignore_modifications do
62
+ unless record.changed_attributes.key?(name)
63
+ original = dup
64
+ end
65
+
66
+ result = yield
67
+
68
+ organize_collection
69
+
70
+ if !record.changed_attributes.key?(name) && original != self
71
+ record.changed_attributes[name] = original
72
+ end
73
+
74
+ record.attributes[name] = self
75
+
76
+ result
77
+ end
78
+ end
79
+ end
80
+
81
+ # A hook to allow implementing classes to muck with the collection
82
+ # before we check it for equality.
83
+ def organize_collection
84
+ # No-op
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,14 @@
1
+ module DatastaxRails
2
+ module Types
3
+ # A collection type that allows you to store ordered arrays in Cassandra.
4
+ # Changes are tracked by hooking into ActiveModel's built-in change
5
+ # tracking.
6
+ class DynamicList < Array
7
+ include DirtyCollection
8
+
9
+ def initialize(record, name, collection)
10
+ super(record, name, collection || [])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ module DatastaxRails
2
+ module Types
3
+ # A collection type that allows you to store key/value pairs in Cassandra.
4
+ # Changes are tracked by hooking into ActiveModel's built-in change
5
+ # tracking.
6
+ #
7
+ # Keys are converted to have the name of the collection prefixed
8
+ # to them as this is how the Solr/Cassandra integration converts
9
+ # between them and dynamic fields.
10
+ class DynamicMap < ActiveSupport::HashWithIndifferentAccess
11
+ include DirtyCollection
12
+
13
+ def dup
14
+ self.class.new(record, name, self).tap do |new_hash|
15
+ new_hash.default = default
16
+ end
17
+ end
18
+
19
+ def [](key)
20
+ super(convert_key(key))
21
+ end
22
+
23
+ protected
24
+ def convert_key(key)
25
+ unless key.to_s.starts_with?(name)
26
+ key = name + key.to_s
27
+ end
28
+ super(key)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ module DatastaxRails
2
+ module Types
3
+ # A collection type that allows you to store an un-ordered, unique
4
+ # set of entries. Changes are tracked by hooking into ActiveModel's
5
+ # built-in change tracking.
6
+ class DynamicSet < Set
7
+ include DirtyCollection
8
+ end
9
+ end
10
+ end
@@ -1,12 +1,11 @@
1
1
  module DatastaxRails
2
2
  module SolrRepair
3
3
  def repair_solr
4
- my_attrs = self.attributes.symbolize_keys.reject do |k,v|
5
- v.nil? ||
6
- !(self.class.attribute_definitions[k].coder.options[:stored] ||
7
- self.class.attribute_definitions[k].coder.options[:indexed])
4
+ encoded = {}
5
+ self.attributes.keys.each do |column_name|
6
+ value = self.read_attribute(column_name)
7
+ encoded[column_name.to_s] = self.class.column_for_attribute(column_name).type_cast_for_solr(value)
8
8
  end
9
- encoded = self.class.encode_attributes(my_attrs).merge(:id => self.id)
10
9
  xml_doc = RSolr::Xml::Generator.new.add(encoded)
11
10
  self.class.solr_connection.update(:data => xml_doc, :params => {:replacefields => false})
12
11
  end
@@ -1,5 +1,5 @@
1
1
  module DatastaxRails
2
- class RecordInvalid < StandardError
2
+ class RecordInvalid < DatastaxRailsError
3
3
  attr_reader :record
4
4
  def initialize(record)
5
5
  @record = record
@@ -11,14 +11,10 @@ module DatastaxRails
11
11
  extend ActiveSupport::Concern
12
12
  include ActiveModel::Validations
13
13
 
14
- included do
15
- define_model_callbacks :validation
16
- define_callbacks :validate, :scope => :name
17
- end
18
-
19
14
  module ClassMethods
20
15
  def create!(attributes = {})
21
16
  new(attributes).tap do |object|
17
+ yield(object) if block_given?
22
18
  object.save!
23
19
  end
24
20
  end
@@ -34,11 +30,9 @@ module DatastaxRails
34
30
  # Validations with no <tt>:on</tt> option will run no matter the context. Validations with
35
31
  # some <tt>:on</tt> option will only run in the specified context.
36
32
  def valid?(context = nil)
37
- run_callbacks :validation do
38
- context ||= (new_record? ? :create : :update)
39
- output = super(context)
40
- errors.empty? && output
41
- end
33
+ context ||= (new_record? ? :create : :update)
34
+ output = super(context)
35
+ errors.empty? && output
42
36
  end
43
37
 
44
38
  def save(options={})
@@ -51,7 +45,7 @@ module DatastaxRails
51
45
 
52
46
  protected
53
47
  def perform_validations(options={})
54
- (options[:validate] != false) ? valid? : true
48
+ options[:validate] == false || valid?(options[:context])
55
49
  end
56
50
  end
57
51
  end