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 | |