1
votes

I'm trying to build up on the following tutorial from railscast: http://railscasts.com/episodes/196-nested-model-form-part-1

I'm trying to make everything work with mongodb and mongoid.

the scenario is: I want to creates events linked to a location. Each events (dance class) contains many lessons. So I thought that an embedded relationship would be perfect.

Here are my models

model Lesson

class Lesson
  include Mongoid::Document
  include Mongoid::Slug
  field :name, :type => String

  embedded_in :event

  slug :name
end

model Event

class Event
  include Mongoid::Document
  include Mongoid::Slug
  include Mongoid::Timestamps
  include Mongoid::MultiParameterAttributes

  field :name, :type => String
  field :description, :type => String
  field :date, :type => DateTime

  validates_presence_of :name

  has_one :venue
  referenced_in :venue
  embeds_many :lessons

  slug :name 
end

model Venue

class Venue
  include Mongoid::Document
  include Mongoid::Slug
  include Mongoid::Timestamps
  include Mongoid::MultiParameterAttributes


  field :name, :type => String
  field :location, :type => String

  validates_presence_of :name, :location

  belongs_to :event

  slug :name
end

event controller

def create
  @event = Event.new(params[:event])
    if @event.save
    flash[:notice] = 'Event was successfully created.'
  end
 respond_with(@Event, :location => events_url)
end

def update
  # @event = Event.find(params[:id])
   @event = Event.find_by_slug(params[:id])
   if @event.update_attributes(params[:event])
      flash[:notice] = "Event was succesfully updated"
    end
  respond_with(@event)
end

Then I have my Event view where I can create events and link it to a Venue. But I'd like to be abe to create the lessons from the Event view/model.

so I used the fields_for to generate a field linked to the Lessons model.

= form_for @event do |f|
  .field
    = f.label :name
    %br/
    = f.text_field :name
  .field
    = f.label :description
    %br/
    = f.text_area :description
  .field
    = f.label :venue_id
    %br/
    = f.collection_select :venue_id, Venue.all, :id, :name
  .field
    = f.label :date
    %br/
    = f.datetime_select :date
  %h3 Add a Class
    = f.fields_for :lessons do |builder|
     = render "lesson_fields", :f => builder
 .actions
    = f.submit 'Save'

When I create or edit a new event I get an error message:

undefined method `extract_id' for "test":String

But the request parameter message on the error page shows my lessons value in the Event document.

"lessons"=>{"name"=>"test name lesson"}

When I remove the fields_for line, everything works fine. But then i don't know how to save the value for the nested documents.

4
can you post the exact code you use to create the Event, including parameters? extract_id is a Method in Mongoid::Criteria btw.Tilo
I've edited the question with the controller info (create and update) where the action fails. I have also corrected the field name as you mentionned, but it's still not working :(Yannick Schall
quick question, should the embedded document have an id? "lessons"=>{"name"=>"test name lesson", lesson_id="xxxxxxxxxxxx"}Yannick Schall
the embedded lessons array will contain an id for each lesson in the embedded collection -- assigned by Mongodb/MongoidTilo
so if i get this on the error page, is it normal? gist.github.com/1361107Yannick Schall

4 Answers

1
votes

I have same problem with embeds_many, but when i try change to has_many. It works!. Maybe you can try too.

0
votes
  • can you post the exact code you use to create the Event, including parameters?

  • which version of Mongoid and Rails are you using?

First thing I noticed is that the following parameter hash does not match your Lessons model:

"lessons"=>{"content"=>"test name lesson"}   # this looks wrong

this should be:

"lessons"=>{"name" => "test name lesson"}

Looks like your lessons form has the wrong label for the text input field .. it should be :name , not :content


To dry things up, you might want to try if the 'nested_form' gem works for you:

after installing the gem, use the nested_form_for instead of form_for in your view.

Check here for a more detailed description:

How can I handle this type of multi level forms in rails

See:

https://github.com/ryanb/nested_form (it's also referenced in the RailsCast you mentioned)


You also might want to check this:

field_for and nested form with mongoid

0
votes

The conclusion of this story is... I removed everything related to mongoid_slug and it started to work. I then put everything back as it was to try to find out how to make it work with mongoid_slug and it just worked, like out of the box.

:(

0
votes

Please include the following code in model event.rb

**accepts_nested_attributes_for :lessons**

This will fix your problem