This commit is contained in:
Didier Lafforgue 2012-03-28 17:33:20 +02:00
parent 11d92ab80e
commit 3f6e7acda6
10 changed files with 93 additions and 23 deletions

View File

@ -17,13 +17,13 @@ GIT
GIT GIT
remote: git://github.com/locomotivecms/custom_fields.git remote: git://github.com/locomotivecms/custom_fields.git
revision: e54c3ddfce0e24668d02c372c6143a722718e215 revision: 5b0e68859eaca41ac9d7a0231c6cd68ad66018b8
branch: 2.0.0.rc branch: 2.0.0.rc
specs: specs:
custom_fields (2.0.0.rc8) custom_fields (2.0.0.rc9)
activesupport (~> 3.2.1) activesupport (~> 3.2.1)
carrierwave-mongoid (~> 0.1.3) carrierwave-mongoid (~> 0.1.3)
mongoid (~> 2.4.5) mongoid (~> 2.4.7)
PATH PATH
remote: . remote: .
@ -36,7 +36,7 @@ PATH
carrierwave-mongoid (~> 0.1.3) carrierwave-mongoid (~> 0.1.3)
cells (~> 3.8.0) cells (~> 3.8.0)
codemirror-rails (~> 2.21) codemirror-rails (~> 2.21)
custom_fields (~> 2.0.0.rc8) custom_fields (~> 2.0.0.rc9)
devise (~> 1.5.3) devise (~> 1.5.3)
dragonfly (~> 0.9.8) dragonfly (~> 0.9.8)
flash_cookie_session (~> 1.1.1) flash_cookie_session (~> 1.1.1)
@ -112,8 +112,8 @@ GEM
xpath (~> 0.1.4) xpath (~> 0.1.4)
carrierwave (0.5.8) carrierwave (0.5.8)
activesupport (~> 3.0) activesupport (~> 3.0)
carrierwave-mongoid (0.1.3) carrierwave-mongoid (0.1.4)
carrierwave (>= 0.5.6) carrierwave (~> 0.5.6)
mongoid (~> 2.1) mongoid (~> 2.1)
cells (3.8.3) cells (3.8.3)
actionpack (~> 3.0) actionpack (~> 3.0)
@ -175,7 +175,7 @@ GEM
formtastic (2.0.2) formtastic (2.0.2)
rails (~> 3.0) rails (~> 3.0)
fssm (0.2.8.1) fssm (0.2.8.1)
gherkin (2.9.1) gherkin (2.9.3)
json (>= 1.4.6) json (>= 1.4.6)
haml (3.1.4) haml (3.1.4)
highline (1.6.11) highline (1.6.11)
@ -188,7 +188,7 @@ GEM
jquery-rails (1.0.19) jquery-rails (1.0.19)
railties (~> 3.0) railties (~> 3.0)
thor (~> 0.14) thor (~> 0.14)
json (1.6.5) json (1.6.6)
kaminari (0.13.0) kaminari (0.13.0)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
@ -302,10 +302,10 @@ GEM
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
tzinfo (0.3.32) tzinfo (0.3.32)
uglifier (1.2.3) uglifier (1.2.4)
execjs (>= 0.3.0) execjs (>= 0.3.0)
multi_json (>= 1.0.2) multi_json (>= 1.0.2)
unicorn (4.2.0) unicorn (4.2.1)
kgio (~> 2.6) kgio (~> 2.6)
rack rack
raindrops (~> 0.7) raindrops (~> 0.7)

View File

@ -73,18 +73,20 @@ class Locomotive.Views.ContentEntries.FormView extends Locomotive.Views.Shared.F
new_entry = new Locomotive.Models.ContentEntry(@options["#{name}_new_entry"]) 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 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: -> enable_many_to_many_fields: ->
_.each @model.get('many_to_many_custom_fields'), (field) => _.each @model.get('many_to_many_custom_fields'), (field) =>
name = field[0] name = field[0]
view = new Locomotive.Views.Shared.Fields.ManyToManyView model: @model, name: name, all_entries: @options["all_#{name}_entries"] 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: -> slugify_label_field: ->
@$('li.input.highlighted > input[type=text]').slugify(target: @$('#content_entry__slug')) @$('li.input.highlighted > input[type=text]').slugify(target: @$('#content_entry__slug'))

View File

@ -34,6 +34,9 @@ class Locomotive.Views.Shared.Fields.HasManyView extends Backbone.View
return @ return @
ui_enabled: ->
@template()?
insert_entries: -> insert_entries: ->
if @collection.length > 0 if @collection.length > 0
@collection.each (entry) => @insert_entry(entry) @collection.each (entry) => @insert_entry(entry)

View File

@ -39,6 +39,9 @@ class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View
return @ return @
ui_enabled: ->
@template()?
insert_entries: -> insert_entries: ->
if @collection.length > 0 if @collection.length > 0
@collection.each (entry) => @insert_entry(entry) @collection.each (entry) => @insert_entry(entry)

View File

@ -43,7 +43,7 @@ module Locomotive
hash[meth]= (if self.source.custom_fields_methods.include?(meth.to_s) hash[meth]= (if self.source.custom_fields_methods.include?(meth.to_s)
if self.source.is_a_custom_field_many_relationship?(meth.to_s) if self.source.is_a_custom_field_many_relationship?(meth.to_s)
# go deeper # 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 else
self.source.send(meth) rescue nil self.source.send(meth) rescue nil
end end

View File

@ -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 %}
<h1>Projects for {{ article.title }}</h1>
<ul>
{% for project in article.projects %}<li>{{ project.name }}</li>
{% endfor %}
</ul>
"""
When I view the rendered page at "/article-projects"
Then the rendered output should look like:
"""
<h1>Projects for Hello world</h1>
<ul>
<li>My sexy project</li>
<li>Baz project</li>
<li>Foo project</li>
</ul>
"""

View File

@ -41,7 +41,7 @@ Given %r{^I set up a many_to_many relationship between "([^"]*)" and "([^"]*)"$}
:label => last_name, :label => last_name,
:type => 'many_to_many', :type => 'many_to_many',
:class_name => last_model.klass_with_custom_fields(:entries).to_s, :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 first_model.save
@ -50,12 +50,22 @@ Given %r{^I set up a many_to_many relationship between "([^"]*)" and "([^"]*)"$}
:label => first_name, :label => first_name,
:type => 'many_to_many', :type => 'many_to_many',
:class_name => first_model.klass_with_custom_fields(:entries).to_s, :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 last_model.save
end 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 Then /^I should be able to view a paginated list of a has many association$/ do
# Create models # Create models
step %{I have an "Articles" model which has many "Comments"} step %{I have an "Articles" model which has many "Comments"}

View File

@ -45,7 +45,7 @@ module Locomotive
if not @@forbidden_attributes.include?(meth.to_s) if not @@forbidden_attributes.include?(meth.to_s)
value = self._source.send(meth) value = self._source.send(meth)
if value.respond_to?(:all) if value.respond_to?(:all) # check for an association
filter_and_order_list(value) filter_and_order_list(value)
else else
value value
@ -70,7 +70,7 @@ module Locomotive
end end
else else
list.ordered list.ordered
end.all end
end end
end end

View File

@ -30,7 +30,7 @@ Gem::Specification.new do |s|
s.add_dependency 'mongoid', '~> 2.4.5' s.add_dependency 'mongoid', '~> 2.4.5'
s.add_dependency 'locomotive-mongoid-tree', '~> 0.6.2' 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' s.add_dependency 'kaminari', '~> 0.13.0'

View File

@ -13,7 +13,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do
it 'loops through the list' do it 'loops through the list' do
template = %({% for project in category.projects %}{{ project }},{% endfor %}) 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,' render(template, { 'category' => @category }).should == 'a,b,'
end end
@ -21,7 +21,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do
it 'filters the list' do it 'filters the list' do
template = %({% with_scope order_by: 'name ASC', active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %}) 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) @list.expects(:where).with({ 'active' => true }).returns(@list)
render(template, { 'category' => @category }).should == 'a,b,' 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 it 'filters the list and uses the default order' do
template = %({% with_scope active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %}) 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) @list.expects(:where).with({ 'active' => true }).returns(@list)
render(template, { 'category' => @category }).should == 'a,b,' render(template, { 'category' => @category }).should == 'a,b,'