belongs_to implemented (tests pass), refactoring will be done once the other associations will be implemented

did committed Mar 02, 2015
commit 8da7f17dde2239580b22d7fb43eb080e38782af6
Showing 9 changed files with 73 additions and 40 deletions
locomotive/steam/adapters/filesystem.rb b/lib/locomotive/steam/adapters/filesystem.rb +2 -2
@@ @@ -43,8 +43,6 @@ module Locomotive::Steam
''
end
- private
-
def identifier_name(mapper)
case mapper.name
when :content_types then :slug
@@ @@ -54,6 +52,8 @@ module Locomotive::Steam
end
end
+ private
+
def _query(mapper, scope, &block)
Locomotive::Steam::Adapters::Memory::Query.new(all(mapper, scope), scope.locale, &block)
end
locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb b/lib/locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb +6 -6
@@ @@ -34,26 +34,26 @@ module Locomotive::Steam
def set_slug(entry, dataset)
if entry._label.respond_to?(:translations) # localized?
entry._label.each do |locale, label|
- entry[:_slug][locale] ||= slugify(label, dataset, locale)
+ entry[:_slug][locale] ||= slugify(entry._id, label, dataset, locale)
end
else
- entry[:_slug][locale] = slugify(entry._label, dataset)
+ entry[:_slug][locale] = slugify(entry._id, entry._label, dataset)
end
end
- def slugify(label, dataset, locale = nil)
+ def slugify(id, label, dataset, locale = nil)
base, index = label.permalink(false), nil
_slugify = -> (i) { [base, i].compact.join('-') }
- while !is_slug_unique?(_slugify.call(index), dataset, locale)
+ while !is_slug_unique?(id, _slugify.call(index), dataset, locale)
index = index ? index + 1 : 1
end
_slugify.call(index)
end
- def is_slug_unique?(slug, dataset, locale)
- dataset.query(locale) { where(_slug: slug) }.first.nil?
+ def is_slug_unique?(id, slug, dataset, locale)
+ dataset.query(locale) { where(_slug: slug, k(:_id, :ne) => id) }.first.nil?
end
end
locomotive/steam/entities/content_type.rb b/lib/locomotive/steam/entities/content_type.rb +0 -8
@@ @@ -26,14 +26,6 @@ module Locomotive::Steam
end)
end
- # def belongs_to_fields
- # self.fields.belongs_to
- # end
-
- # def localized_fields_names
- # self.fields.localized_fields_names
- # end
-
def label_field_name
(self[:label_field_name] || fields.first.name).to_sym
end
locomotive/steam/entities/content_type_field.rb b/lib/locomotive/steam/entities/content_type_field.rb +10 -0
@@ @@ -25,6 +25,16 @@ module Locomotive::Steam
alias :target :class_name
+ def target_id
+ return @target_id if @target_id
+
+ @target_id = if self.target =~ /^Locomotive::ContentEntry(.*)$/o
+ $1
+ else
+ self.target
+ end
+ end
+
def required?; self[:required]; end
def localized?; self[:localized]; end
locomotive/steam/liquid/drops/content_types.rb b/lib/locomotive/steam/liquid/drops/content_types.rb +1 -1
@@ @@ -58,7 +58,7 @@ module Locomotive
end
def collection
- # TODO: repository.for(@content_type).all(....)
+ # TODO: repository.with(@content_type).all(....)
@collection ||= repository.all(@content_type, @context['with_scope'])
end
locomotive/steam/models/associations/belongs_to.rb b/lib/locomotive/steam/models/associations/belongs_to.rb +6 -2
@@ @@ -4,18 +4,20 @@ require 'morphine'
module Locomotive::Steam
module Models
- # Note: represents an embedded collection
class BelongsToAssociation
attr_reader :repository
- def initialize(repository_klass, scope, adapter)
+ def initialize(repository_klass, scope, adapter, &block)
# build a new instance of the target repository
@repository = repository_klass.new(adapter)
# Note: if we change the locale of the parent repository, that won't
# reflect in that repository
@repository.scope = scope.dup
+
+ # the block will executed when a method of the target will be called
+ @block = block_given? ? block : nil
end
def attach(name, entity)
@@ @@ -27,6 +29,8 @@ module Locomotive::Steam
end
def method_missing(name, *args, &block)
+ @block.call(@repository) if @block
+
target = @repository.find(target_id)
# replace the proxy class by the real target entity
locomotive/steam/models/mapper.rb b/lib/locomotive/steam/models/mapper.rb +6 -6
@@ @@ -23,8 +23,8 @@ module Locomotive::Steam
@default_attributes += [[name.to_sym, value]]
end
- def belongs_to_association(name, repository_klass, options = {})
- @associations[:belongs_to] += [[name.to_sym, repository_klass, options]]
+ def belongs_to_association(name, repository_klass, &block)
+ @associations[:belongs_to] += [[name.to_sym, repository_klass, block]]
end
def embedded_association(name, repository_klass)
@@ @@ -68,15 +68,15 @@ module Locomotive::Steam
# build the embedded associations
def serialize_embedded_associations(attributes)
- @associations[:embedded].each do |name, repository_klass|
+ @associations[:embedded].each do |(name, repository_klass)|
attributes[name] = EmbeddedAssociation.new(repository_klass, attributes[name], @repository.scope)
end
end
# build the belongs_to associations
def serialize_belongs_to_associations(attributes)
- @associations[:belongs_to].each do |name, repository_klass, options|
- attributes[name] = BelongsToAssociation.new(repository_klass, @repository.scope, @repository.adapter)
+ @associations[:belongs_to].each do |(name, repository_klass, block)|
+ attributes[name] = BelongsToAssociation.new(repository_klass, @repository.scope, @repository.adapter, &block)
end
end
@@ @@ -89,7 +89,7 @@ module Locomotive::Steam
def attach_entity_to_belongs_to_associations(entity)
@associations[:belongs_to].each do |(name, _)|
- entity[name].attach(name, entity) # Note: entity[name] is a proxy class
+ entity[name].attach(name, entity)
end
end
locomotive/steam/repositories/content_entry_repository.rb b/lib/locomotive/steam/repositories/content_entry_repository.rb +30 -10
@@ @@ -5,8 +5,7 @@ module Locomotive
include Models::Repository
- attr_reader :content_type_repository
- attr_accessor :content_type, :local_conditions
+ attr_accessor :content_type_repository, :content_type, :local_conditions
def initialize(adapter, site = nil, locale = nil, content_type_repository = nil)
@local_conditions = {}
@@ @@ -43,6 +42,12 @@ module Locomotive
query { where(conditions).order_by(order_by) }.all
end
+ def find(id)
+ name = adapter.identifier_name(mapper)
+ conditions = prepare_conditions(name => id)
+ first { where(conditions) }
+ end
+
def exists?(conditions = {})
conditions = prepare_conditions(conditions)
query { where(conditions) }.all.size > 0
@@ @@ -82,15 +87,30 @@ module Locomotive
def mapper(memoized = false)
super(memoized).tap do |mapper|
- unless self.content_type.localized_fields_names.blank?
- mapper.localized_attributes(*self.content_type.localized_fields_names)
- end
+ add_localized_fields_to_mapper(mapper)
+ add_belongs_to_fields_to_mapper(mapper)
+ end
+ end
+
+ def add_localized_fields_to_mapper(mapper)
+ unless self.content_type.localized_fields_names.blank?
+ mapper.localized_attributes(*self.content_type.localized_fields_names)
+ end
+ end
+
+ def add_belongs_to_fields_to_mapper(mapper)
+ self.content_type.belongs_to_fields.each do |field|
+ mapper.belongs_to_association(field.name, self.class) do |repository|
+ # Note: this code will be executed only when the attribute will be called
+
+ # load the target content type
+ _content_type = content_type_repository.find(field.target_id)
+
+ # the target repository uses this content type for all the other inner calls
+ repository.with(_content_type)
- self.content_type.belongs_to_fields.each do |field|
- mapper.belongs_to_association(field.name, self.class, {}) do |repository|
- # TODO: load the content type (adapter.id_names[:content_types])
- repository.content_type
- end # field.association_options)
+ # the content type repository is also need by the target repository
+ repository.content_type_repository = content_type_repository
end
end
end
spec/unit/repositories/content_entry_repository_spec.rb +12 -5
@@ @@ -20,21 +20,28 @@ describe Locomotive::Steam::ContentEntryRepository do
describe 'belongs_to' do
- let(:field) { instance_double('Field', name: :author, type: :belongs_to, association_options: { class_name: 'authors' }) }
- let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: nil, label_field_name: :title, belongs_to_fields: [field], fields_by_name: { title: instance_double('Field', name: :title, type: :string), author: field }, localized_fields_names: []) }
- let(:other_type) { instance_double('Authors', _id: 2, slug: 'authors', order_by: nil, label_field_name: :name, fields_by_name: { name: instance_double('Field', name: :name, type: :string) }, localized_fields_names: []) }
- let(:entries) { [{ content_type_id: 1, title: 'Hello world', author_id: 'john-doe' }] }
+ let(:field) { instance_double('Field', name: :author, type: :belongs_to, target_id: 2) }
+ let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: nil, label_field_name: :title, belongs_to_fields: [field], fields_by_name: { title: instance_double('Field', name: :title, type: :string), author: field }, localized_fields_names: []) }
+ let(:entries) { [{ content_type_id: 1, title: 'Hello world', author_id: 'john-doe' }] }
+ let(:other_type) { instance_double('Authors', _id: 2, slug: 'authors', order_by: nil, label_field_name: :name, belongs_to_fields: [], fields_by_name: { name: instance_double('Field', name: :name, type: :string) }, localized_fields_names: []) }
+ let(:other_entries) { [{ content_type_id: 2, _slug: 'john-doe', name: 'John Doe' }] }
let(:type_repository) { instance_double('ContentTypeRepository', belongs_to: [field]) }
before do
allow(type).to receive(:fields).and_return(type_repository)
+ allow(content_type_repository).to receive(:find).with(2).and_return(other_type)
end
subject { repository.with(type).by_slug('hello-world') }
it { expect(subject.author.class).to eq Locomotive::Steam::Models::BelongsToAssociation }
- # it { expect(subject.author.name).to eq 'John Doe' }
+
+ it 'calls the new repository to fetch the target entity' do
+ author = subject.author
+ allow(adapter).to receive(:collection).and_return(other_entries)
+ expect(author.name).to eq 'John Doe'
+ end
end