the with_scope liquid tag accepts a slug if querying a belongs_to field

did committed Sep 26, 2016
commit a2cba33b3e70c3bb1f08465a6e4a75f469a43e85
Showing 5 changed files with 56 additions and 26 deletions
locomotive/steam/adapters/mongodb.rb b/lib/locomotive/steam/adapters/mongodb.rb +5 -1
@@ @@ -52,7 +52,11 @@ module Locomotive::Steam
end
def make_id(id)
- BSON::ObjectId.from_string(id)
+ begin
+ BSON::ObjectId.from_string(id)
+ rescue BSON::ObjectId::Invalid
+ false
+ end
end
def base_url(mapper, scope, entity = nil)
locomotive/steam/repositories/content_entry_repository.rb b/lib/locomotive/steam/repositories/content_entry_repository.rb +32 -13
@@ @@ -22,8 +22,12 @@ module Locomotive
default_attribute :content_type, -> (repository) { repository.content_type }
end
- # this is the starting point of all the next methods
+ # this is the starting point of all the next methods.
+ # type can be either an instance of the ContentTypeRepository class
+ # or the id of a content type.
def with(type)
+ type = self.content_type_repository.find(type) if type.is_a?(String)
+
self.content_type = type # used for creating the scope
self.scope.context[:content_type] = type
@@ @@ -131,11 +135,15 @@ module Locomotive
end
def prepare_conditions(*conditions)
- _conditions = Conditions.new(adapter, conditions.first, self.content_type.fields).prepare
+ _conditions = Conditions.new(conditions.first, self.content_type.fields, simple_clone).prepare
super({ _visible: true }, _conditions)
end
+ def simple_clone
+ self.class.new(self.adapter, self.site, self.locale, self.content_type_repository)
+ end
+
def add_localized_fields_to_mapper(mapper)
unless self.content_type.localized_names.blank?
mapper.localized_attributes(*self.content_type.localized_names)
@@ @@ -185,10 +193,10 @@ module Locomotive
class Conditions
- def initialize(adapter, conditions = {}, fields)
- @adapter = adapter
+ def initialize(conditions = {}, fields, target_repository)
@conditions = conditions.try(:with_indifferent_access) || {}
@fields, @operators = fields, {}
+ @target_repository = target_repository
@conditions.each do |name, value|
_name, operator = name.to_s.split('.')
@@ @@ -206,10 +214,10 @@ module Locomotive
_prepare(@fields.dates_and_date_times) { |field, value| value_to_date(value, field.type) }
# belongs_to
- _prepare(@fields.belongs_to) { |field, value| value_to_id(value) }
+ _prepare(@fields.belongs_to) { |field, value| value_to_id(value, field.target_id) }
# many_to_many
- _prepare(@fields.many_to_many) { |field, value| values_to_ids(value) }
+ _prepare(@fields.many_to_many) { |field, value| values_to_ids(value, field.target_id) }
@conditions
end
@@ @@ -237,16 +245,31 @@ module Locomotive
end
end
- def value_to_id(value)
+ def values_to_ids(value, target_id)
+ [*value].map { |_value| value_to_id(_value, target_id) }
+ end
+
+ def value_to_id(value, target_id)
_value = if value.is_a?(Hash)
value['_id'] || value[:_id]
elsif value.respond_to?(:each) # array
- values_to_ids(value)
+ values_to_ids(value, target_id)
else
value.respond_to?(:_id) ? value._id : value
end
- @adapter.make_id(_value)
+ if (id = @target_repository.adapter.make_id(_value)) == false
+ slug_to_id(value, target_id)
+ else
+ id
+ end
+ end
+
+ def slug_to_id(slug, target_id)
+ if _repository = @target_repository.with(target_id)
+ _entry = _repository.first { where(_slug: slug).only(:_id) }
+ _entry.try(:_id)
+ end
end
def value_to_date(value, type)
@@ @@ -259,10 +282,6 @@ module Locomotive
type == :date ? _value.to_date : _value.to_datetime
end
- def values_to_ids(value)
- [*value].map { |_value| value_to_id(_value) }
- end
-
end
end
spec/integration/repositories/content_entry_repository_spec.rb +15 -9
@@ @@ -7,11 +7,13 @@ describe Locomotive::Steam::ContentEntryRepository do
shared_examples_for 'a repository' do
- let(:site) { Locomotive::Steam::Site.new(_id: site_id, locales: %w(en fr nb)) }
- let(:locale) { :en }
- let(:type_repository) { Locomotive::Steam::ContentTypeRepository.new(adapter, site, locale) }
- let(:repository) { described_class.new(adapter, site, locale, type_repository).with(type) }
- let(:type) { type_repository.by_slug('bands') }
+ let(:site) { Locomotive::Steam::Site.new(_id: site_id, locales: %w(en fr nb)) }
+ let(:locale) { :en }
+ let(:type_repository) { Locomotive::Steam::ContentTypeRepository.new(adapter, site, locale) }
+ let(:repository) { described_class.new(adapter, site, locale, type_repository).with(type) }
+ let(:type) { type_repository.by_slug('bands') }
+ let(:target_type) { type_repository.by_slug('songs') }
+ let(:target_repository) { described_class.new(adapter, site, locale, type_repository).with(target_type) }
describe '#all' do
subject { repository.all }
@@ @@ -55,6 +57,11 @@ describe Locomotive::Steam::ContentEntryRepository do
it { expect(subject.map { |entry| entry[:name] }).to eq(['Alice in Chains', 'Pearl Jam']) }
end
+ describe 'filter by a belongs_to field' do
+ subject { target_repository.all(band: 'the-who') }
+ it { expect(subject.map { |entry| entry[:title] }).to eq(['Song #5', 'Song #6']) }
+ end
+
describe '#group_by_select_option' do
subject { repository.group_by_select_option(:kind) }
it { expect(subject.map { |h| h[:name] }).to eq(%w(grunge rock country)) }
@@ @@ -73,9 +80,8 @@ describe Locomotive::Steam::ContentEntryRepository do
describe '#create' do
- let(:type) { type_repository.by_slug('songs') }
- let(:attributes) { { title: 'Jeremy', band: 'pearl-jam', short_description: '"Jeremy" is a song by the American rock band Pearl Jam' } }
- let(:entry) { repository.with(type).build(attributes) }
+ let(:attributes) { { title: 'Jeremy', band_id: 'pearl-jam', short_description: '"Jeremy" is a song by the American rock band Pearl Jam' } }
+ let(:entry) { repository.with(target_type).build(attributes) }
subject { repository.create(entry) }
@@ @@ -89,7 +95,7 @@ describe Locomotive::Steam::ContentEntryRepository do
describe '#inc' do
let(:type) { type_repository.by_slug('songs') }
- let(:attributes) { { title: 'Jeremy', band: 'pearl-jam', short_description: '"Jeremy" is a song by the American rock band Pearl Jam', views: 41 } }
+ let(:attributes) { { title: 'Jeremy', band_id: 'pearl-jam', short_description: '"Jeremy" is a song by the American rock band Pearl Jam', views: 41 } }
let(:entry) { repository.with(type).build(attributes) }
before { repository.create(entry) }
spec/support/mongo.rb +2 -1
@@ @@ -1,3 +1,4 @@
require 'mongo'
- Mongo::Logger.logger.level = Logger::INFO # DEBUG # INFO
+ Mongo::Logger.logger.level = Logger::INFO
+ # Mongo::Logger.logger.level = Logger::DEBUG
spec/unit/repositories/content_entry_repository_spec.rb +2 -2
@@ @@ -407,7 +407,7 @@ describe Locomotive::Steam::ContentEntryRepository do
context 'belongs_to fields' do
let(:value) { 42 }
- let(:field) { instance_double('BelongsToField', name: 'person', persisted_name: 'person_id') }
+ let(:field) { instance_double('BelongsToField', name: 'person', persisted_name: 'person_id', target_id: '42') }
let(:_fields) { instance_double('Fields', selects: [], belongs_to: [field], many_to_many: [], dates_and_date_times: []) }
let(:conditions) { { 'person' => value } }
@@ @@ -450,7 +450,7 @@ describe Locomotive::Steam::ContentEntryRepository do
context 'many_to_many fields' do
let(:value) { 42 }
- let(:field) { instance_double('ManyToManyField', name: 'tags', persisted_name: 'tag_ids') }
+ let(:field) { instance_double('ManyToManyField', name: 'tags', persisted_name: 'tag_ids', target_id: '42') }
let(:_fields) { instance_double('Fields', selects: [], belongs_to: [], many_to_many: [field], dates_and_date_times: []) }
let(:conditions) { { 'tags.in' => value } }