diff --git a/Gemfile.lock b/Gemfile.lock index c14da849..8a7c0223 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,13 +17,13 @@ GIT GIT remote: git://github.com/locomotivecms/custom_fields.git - revision: e54c3ddfce0e24668d02c372c6143a722718e215 + revision: 5b0e68859eaca41ac9d7a0231c6cd68ad66018b8 branch: 2.0.0.rc specs: - custom_fields (2.0.0.rc8) + custom_fields (2.0.0.rc9) activesupport (~> 3.2.1) carrierwave-mongoid (~> 0.1.3) - mongoid (~> 2.4.5) + mongoid (~> 2.4.7) PATH remote: . @@ -36,7 +36,7 @@ PATH carrierwave-mongoid (~> 0.1.3) cells (~> 3.8.0) codemirror-rails (~> 2.21) - custom_fields (~> 2.0.0.rc8) + custom_fields (~> 2.0.0.rc9) devise (~> 1.5.3) dragonfly (~> 0.9.8) flash_cookie_session (~> 1.1.1) @@ -112,8 +112,8 @@ GEM xpath (~> 0.1.4) carrierwave (0.5.8) activesupport (~> 3.0) - carrierwave-mongoid (0.1.3) - carrierwave (>= 0.5.6) + carrierwave-mongoid (0.1.4) + carrierwave (~> 0.5.6) mongoid (~> 2.1) cells (3.8.3) actionpack (~> 3.0) @@ -175,7 +175,7 @@ GEM formtastic (2.0.2) rails (~> 3.0) fssm (0.2.8.1) - gherkin (2.9.1) + gherkin (2.9.3) json (>= 1.4.6) haml (3.1.4) highline (1.6.11) @@ -188,7 +188,7 @@ GEM jquery-rails (1.0.19) railties (~> 3.0) thor (~> 0.14) - json (1.6.5) + json (1.6.6) kaminari (0.13.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) @@ -302,10 +302,10 @@ GEM polyglot polyglot (>= 0.3.1) tzinfo (0.3.32) - uglifier (1.2.3) + uglifier (1.2.4) execjs (>= 0.3.0) multi_json (>= 1.0.2) - unicorn (4.2.0) + unicorn (4.2.1) kgio (~> 2.6) rack raindrops (~> 0.7) diff --git a/app/assets/javascripts/locomotive/views/content_entries/_form_view.js.coffee b/app/assets/javascripts/locomotive/views/content_entries/_form_view.js.coffee index a7ca7414..11b1389c 100644 --- a/app/assets/javascripts/locomotive/views/content_entries/_form_view.js.coffee +++ b/app/assets/javascripts/locomotive/views/content_entries/_form_view.js.coffee @@ -73,18 +73,20 @@ class Locomotive.Views.ContentEntries.FormView extends Locomotive.Views.Shared.F new_entry = new Locomotive.Models.ContentEntry(@options["#{name}_new_entry"]) view = new Locomotive.Views.Shared.Fields.HasManyView model: @model, name: name, new_entry: new_entry, inverse_of: inverse_of - @_has_many_field_views.push(view) + if view.ui_enabled() + @_has_many_field_views.push(view) - @$("##{@model.paramRoot}_#{name}_input label").after(view.render().el) + @$("##{@model.paramRoot}_#{name}_input label").after(view.render().el) enable_many_to_many_fields: -> _.each @model.get('many_to_many_custom_fields'), (field) => name = field[0] view = new Locomotive.Views.Shared.Fields.ManyToManyView model: @model, name: name, all_entries: @options["all_#{name}_entries"] - @_many_to_many_field_views.push(view) + if view.ui_enabled() + @_many_to_many_field_views.push(view) - @$("##{@model.paramRoot}_#{name}_input label").after(view.render().el) + @$("##{@model.paramRoot}_#{name}_input label").after(view.render().el) slugify_label_field: -> @$('li.input.highlighted > input[type=text]').slugify(target: @$('#content_entry__slug')) diff --git a/app/assets/javascripts/locomotive/views/shared/fields/has_many_view.js.coffee b/app/assets/javascripts/locomotive/views/shared/fields/has_many_view.js.coffee index 71a328f4..1a1a7e1c 100644 --- a/app/assets/javascripts/locomotive/views/shared/fields/has_many_view.js.coffee +++ b/app/assets/javascripts/locomotive/views/shared/fields/has_many_view.js.coffee @@ -34,6 +34,9 @@ class Locomotive.Views.Shared.Fields.HasManyView extends Backbone.View return @ + ui_enabled: -> + @template()? + insert_entries: -> if @collection.length > 0 @collection.each (entry) => @insert_entry(entry) diff --git a/app/assets/javascripts/locomotive/views/shared/fields/many_to_many_view.js.coffee b/app/assets/javascripts/locomotive/views/shared/fields/many_to_many_view.js.coffee index 65bc982e..01c5c681 100644 --- a/app/assets/javascripts/locomotive/views/shared/fields/many_to_many_view.js.coffee +++ b/app/assets/javascripts/locomotive/views/shared/fields/many_to_many_view.js.coffee @@ -39,6 +39,9 @@ class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View return @ + ui_enabled: -> + @template()? + insert_entries: -> if @collection.length > 0 @collection.each (entry) => @insert_entry(entry) diff --git a/app/presenters/locomotive/content_entry_presenter.rb b/app/presenters/locomotive/content_entry_presenter.rb index 1b2e5722..49c38786 100644 --- a/app/presenters/locomotive/content_entry_presenter.rb +++ b/app/presenters/locomotive/content_entry_presenter.rb @@ -43,7 +43,7 @@ module Locomotive hash[meth]= (if self.source.custom_fields_methods.include?(meth.to_s) if self.source.is_a_custom_field_many_relationship?(meth.to_s) # go deeper - self.source.send(meth).map { |entry| entry.to_presenter(:depth => self.depth + 1) } + self.source.send(meth).ordered.map { |entry| entry.to_presenter(:depth => self.depth + 1) } else self.source.send(meth) rescue nil end diff --git a/features/public/many_to_many.feature b/features/public/many_to_many.feature new file mode 100644 index 00000000..fb496604 --- /dev/null +++ b/features/public/many_to_many.feature @@ -0,0 +1,52 @@ +Feature: Many to Many Association + As a designer + In order to make dealing with models easier + I want to be able to display other models that have a many to many association + + Background: + Given I have the site: "test site" set up + And I have a custom model named "Articles" with + | label | type | required | + | Title | string | true | + | Body | string | false | + And I have a custom model named "Projects" with + | label | type | required | target | + | Name | string | true | | + | Description | text | false | | + And I set up a many_to_many relationship between "Articles" and "Projects" + And I have entries for "Articles" with + | title | body | + | Hello world | Lorem ipsum | + | Lorem ipsum | Lorem ipsum... | + And I have entries for "Projects" with + | name | description | + | My sexy project | Lorem ipsum | + | Foo project | Lorem ipsum... | + | Bar project | Lorem ipsum... | + | Baz project | Lorem ipsum... | + And I attach the "My sexy project" project to the "Hello world" article + And I attach the "Baz project" project to the "Hello world" article + And I attach the "Foo project" project to the "Hello world" article + + Scenario: Displaying the entries of a many to many association + Given a page named "article-projects" with the template: + """ + {% assign article = contents.articles.first %} +

Projects for {{ article.title }}

+ + """ + When I view the rendered page at "/article-projects" + Then the rendered output should look like: + """ + +

Projects for Hello world

+ + """ \ No newline at end of file diff --git a/features/step_definitions/relationships_steps.rb b/features/step_definitions/relationships_steps.rb index e32fb395..48e41700 100644 --- a/features/step_definitions/relationships_steps.rb +++ b/features/step_definitions/relationships_steps.rb @@ -41,7 +41,7 @@ Given %r{^I set up a many_to_many relationship between "([^"]*)" and "([^"]*)"$} :label => last_name, :type => 'many_to_many', :class_name => last_model.klass_with_custom_fields(:entries).to_s, - :inverse_of => first_name.singularize.downcase + :inverse_of => first_name.pluralize.downcase }) first_model.save @@ -50,12 +50,22 @@ Given %r{^I set up a many_to_many relationship between "([^"]*)" and "([^"]*)"$} :label => first_name, :type => 'many_to_many', :class_name => first_model.klass_with_custom_fields(:entries).to_s, - :inverse_of => last_name.singularize.downcase + :inverse_of => last_name.pluralize.downcase }) last_model.save end +Given %r{^I attach the "([^"]*)" ([\S]*) to the "([^"]*)" ([\S]*)$} do |target_name, target_model_name, souce_name, source_model_name| + target_model = @site.content_types.where(:name => target_model_name.pluralize.capitalize).first + source_model = @site.content_types.where(:name => source_model_name.pluralize.capitalize).first + + target_entry = target_model.entries.where(:_slug => target_name.permalink).first + source_entry = source_model.entries.where(:_slug => souce_name.permalink).first + + source_entry.send(target_model_name.pluralize.downcase.parameterize('_').to_sym).push(target_entry) +end + Then /^I should be able to view a paginated list of a has many association$/ do # Create models step %{I have an "Articles" model which has many "Comments"} diff --git a/lib/locomotive/liquid/drops/content_entry.rb b/lib/locomotive/liquid/drops/content_entry.rb index 408e7353..99420387 100644 --- a/lib/locomotive/liquid/drops/content_entry.rb +++ b/lib/locomotive/liquid/drops/content_entry.rb @@ -45,7 +45,7 @@ module Locomotive if not @@forbidden_attributes.include?(meth.to_s) value = self._source.send(meth) - if value.respond_to?(:all) + if value.respond_to?(:all) # check for an association filter_and_order_list(value) else value @@ -70,7 +70,7 @@ module Locomotive end else list.ordered - end.all + end end end diff --git a/locomotive_cms.gemspec b/locomotive_cms.gemspec index 77b1c5ff..f65538b1 100755 --- a/locomotive_cms.gemspec +++ b/locomotive_cms.gemspec @@ -30,7 +30,7 @@ Gem::Specification.new do |s| s.add_dependency 'mongoid', '~> 2.4.5' s.add_dependency 'locomotive-mongoid-tree', '~> 0.6.2' - s.add_dependency 'custom_fields', '~> 2.0.0.rc8' + s.add_dependency 'custom_fields', '~> 2.0.0.rc9' s.add_dependency 'kaminari', '~> 0.13.0' diff --git a/spec/lib/locomotive/liquid/drops/content_entry_spec.rb b/spec/lib/locomotive/liquid/drops/content_entry_spec.rb index f8dac7d8..0b6cd6a1 100644 --- a/spec/lib/locomotive/liquid/drops/content_entry_spec.rb +++ b/spec/lib/locomotive/liquid/drops/content_entry_spec.rb @@ -13,7 +13,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do it 'loops through the list' do template = %({% for project in category.projects %}{{ project }},{% endfor %}) - @list.expects(:ordered).returns(mock('criteria', :all => %w(a b))) + @list.expects(:ordered).returns(%w(a b)) render(template, { 'category' => @category }).should == 'a,b,' end @@ -21,7 +21,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do it 'filters the list' do template = %({% with_scope order_by: 'name ASC', active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %}) - @list.expects(:order_by).with(['name', 'ASC']).returns(mock('criteria', :all => %w(a b))) + @list.expects(:order_by).with(['name', 'ASC']).returns(%w(a b)) @list.expects(:where).with({ 'active' => true }).returns(@list) render(template, { 'category' => @category }).should == 'a,b,' @@ -30,7 +30,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do it 'filters the list and uses the default order' do template = %({% with_scope active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %}) - @list.expects(:ordered).returns(mock('criteria', :all => %w(a b))) + @list.expects(:ordered).returns(%w(a b)) @list.expects(:where).with({ 'active' => true }).returns(@list) render(template, { 'category' => @category }).should == 'a,b,'