Skip to content
Browse files

Add support for Mongoid embedded relations

  • Loading branch information...
1 parent ddd8934 commit 163da3e95a1afcf770e8b6dba8a4b82ad3634647 @mshibuya mshibuya committed
View
1 .gitignore
@@ -12,6 +12,7 @@
/spec/generators/tmp
/spec/lib/tmp
Gemfile.lock
+Gemfile31.lock
coverage/*
db/*.sqlite3
db/*.sqlite3-journal
View
6 app/views/rails_admin/main/_form_nested_many.html.haml
@@ -2,13 +2,15 @@
.btn-group
%a.btn.btn-info.toggler{:'data-toggle' => "button", :'data-target' => "#{form.jquery_namespace(field)} > .tab-content, #{form.jquery_namespace(field)} > .controls > .nav", :class => (field.active? ? 'active' : '')}
%i.icon-white
- = form.link_to_add "<i class=\"icon-plus icon-white\"></i> #{wording_for(:link, :new, field.associated_model_config.abstract_model)}".html_safe, field.name, { :class => 'btn btn-info' }
+ - unless field.nested_form[:update_only]
@bbenezech Collaborator

Haha, nice! I totally overlooked the :update_only option. Cool :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ = form.link_to_add "<i class=\"icon-plus icon-white\"></i> #{wording_for(:link, :new, field.associated_model_config.abstract_model)}".html_safe, field.name, { :class => 'btn btn-info' }
= form.errors_for(field)
= form.help_for(field)
%ul.nav.nav-tabs{ :style => 'margin-top:5px' }
.tab-content
= form.fields_for field.name do |nested_form|
- = nested_form.link_to_remove '<span class="btn btn-small btn-danger"><i class="icon-trash icon-white"></i></span>'.html_safe
+ - if field.nested_form[:allow_destroy]
@bbenezech Collaborator

Less sure about that one. Newly added nested forms should be removable in all cases.

What do you think?

@mshibuya Collaborator

You're right, certainly. I've missed that case.
I'll try to find a way to handle that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ = nested_form.link_to_remove '<span class="btn btn-small btn-danger"><i class="icon-trash icon-white"></i></span>'.html_safe
= nested_form.generate({:action => :nested, :model_config => field.associated_model_config, :nested_in => field.name })
= form.javascript_for(field) do
View
1 config/initializers/mongoid_extensions.rb
@@ -1,4 +1,5 @@
if defined?(::Mongoid::Document)
require 'rails_admin/adapters/mongoid/extension'
Mongoid::Document.send(:include, RailsAdmin::Adapters::Mongoid::Extension)
+ Mongoid::NestedAttributes::ClassMethods.send(:include, RailsAdmin::Adapters::Mongoid::NestedAttributesExtension)
end
View
4 lib/rails_admin/adapters/active_record.rb
@@ -97,6 +97,10 @@ def encoding
Rails.configuration.database_configuration[Rails.env]['encoding']
end
+ def embedded?
+ false
+ end
+
private
def query_conditions(query, fields = config.list.fields.select(&:queryable?))
View
10 lib/rails_admin/adapters/mongoid.rb
@@ -70,7 +70,7 @@ def associations
:polymorphic => association_polymorphic_lookup(association),
:inverse_of => association_inverse_of_lookup(association),
:read_only => nil,
- :nested_form => nil
+ :nested_form => association_nested_attributes_options_lookup(association)
}
end
end
@@ -128,6 +128,10 @@ def encoding
'UTF-8'
end
+ def embedded?
+ @embedded ||= !!model.associations.values.find{|a| a.macro.to_sym == :embedded_in }
+ end
+
private
def query_conditions(query, fields = config.list.fields.select(&:queryable?))
@@ -260,6 +264,10 @@ def association_foreign_type_lookup(association)
end
end
+ def association_nested_attributes_options_lookup(association)
+ model.nested_attributes_options.try { |o| o[association.name.to_sym] }
+ end
+
def association_as_lookup(association)
association.as.try :to_sym
end
View
20 lib/rails_admin/adapters/mongoid/extension.rb
@@ -22,6 +22,26 @@ def safe_send(value)
end
end
end
+
+ module NestedAttributesExtension
+ extend ActiveSupport::Concern
+
+ included do
+ attr_reader :nested_attributes_options
+ alias_method_chain :accepts_nested_attributes_for, :rails_admin
+ end
+
+ # Mongoid accepts_nested_attributes_for does not store options in accessible scope,
+ # so we intercept the call and store it in instance variable which can be accessed from outside
+ def accepts_nested_attributes_for_with_rails_admin(*args)
@bbenezech Collaborator

FieldTest.nested_attributes_options[:nested_field_tests] works out of the box and is part of ActiveModel's API, which is fine for us.

Did I miss smtg?

@mshibuya Collaborator

accepts_nested_attributes_for appears to be implemented independently (and slightly differently) between AR and Mongoid, not being a functionality of ActiveModel.

Out-of-the-box Mongoid model doesn't have nested_attributes_options method, and stores options which is passed to accepts_nested_attributes_for in local block scope which is not accessible from outside.
I wish I could avoid this patchy method, but I could not find the way to bring out that options inside a block.

@bbenezech Collaborator

I assumed there was an ActiveModel's compatibility layer, I got it all the wrong. Sorry I wasted your time !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ @nested_attributes_options = {}
+ options = args.extract_options!
+ args.each do |arg|
+ @nested_attributes_options[arg.to_sym] = options.reverse_merge(:allow_destroy=>false, :update_only=>false)
+ end
+ accepts_nested_attributes_for_without_rails_admin(*args, options)
+ end
+ end
end
end
end
View
2 lib/rails_admin/config.rb
@@ -304,7 +304,7 @@ def reset_model(model)
# @see RailsAdmin::Config::Hideable
def visible_models(bindings)
- models.map{|m| m.with(bindings) }.select{|m| m.visible? && bindings[:controller].authorized?(:index, m.abstract_model)}.sort do |a, b|
+ models.map{|m| m.with(bindings) }.select{|m| m.visible? && bindings[:controller].authorized?(:index, m.abstract_model) && !m.abstract_model.embedded?}.sort do |a, b|
(weight_order = a.weight <=> b.weight) == 0 ? a.label.downcase <=> b.label.downcase : weight_order
end
end
View
2 lib/rails_admin/config/fields/association.rb
@@ -21,7 +21,7 @@ def association
amc = polymorphic? ? RailsAdmin::Config.model(associated) : associated_model_config # perf optimization for non-polymorphic associations
am = amc.abstract_model
wording = associated.send(amc.object_label_method)
- can_see = v.authorized?(:show, am, associated)
+ can_see = v.authorized?(:show, am, associated) && !am.embedded?
can_see = can_see && (show_action = RailsAdmin::Config::Actions.find(:show, { :controller => v.controller, :abstract_model => am, :object => associated }))
can_see ? v.link_to(wording, v.url_for(:action => show_action.action_name, :model_name => am.to_param, :id => associated.id)) : wording
end.to_sentence.html_safe
View
3 spec/dummy_app/app/models/article.rb
@@ -6,4 +6,7 @@ class Article
referenced_in :author
references_and_referenced_in_many :tags
+
+ embeds_many :notes
+ accepts_nested_attributes_for :notes, :allow_destroy => true
end
View
7 spec/dummy_app/app/models/note.rb
@@ -0,0 +1,7 @@
+class Note
+ include Mongoid::Document
+
+ embedded_in :article
+ field :subject, :type => String
+ field :description, :type => String
+end
View
10 spec/integration/config/edit/rails_admin_config_edit_spec.rb
@@ -814,6 +814,16 @@ class Team
visit new_path(:model_name => "field_test")
should have_no_selector('.add_nested_fields')
end
+
+ it 'should work with Mongoid' do
+ RailsAdmin::Config.excluded_models = [RelTest]
+ @record = Article.create :notes => [{:subject => 'nested'}]
+ visit edit_path(:model_name => "article", :id => @record.id)
+ fill_in "article_notes_attributes_0_subject", :with => 'note subject 1 edited'
+ click_button "Save"
+ @record.reload
+ @record.notes[0].subject.should == 'note subject 1 edited'
+ end
end

0 comments on commit 163da3e

Please sign in to comment.
Something went wrong with that request. Please try again.