开发者

Adding a list item client-side

I'll say right off the bat that I'm a complete beginner to Rails, so this might be something obvious that I'm missing.

I have a web form for editing an unordered (<ul>) list of questions. Each question is an item in the list. Each question has a text field for the question text and a dropdown to indicate what type of question it is (multiple choice, true/false, etc).

I want to also give the user the ability to add new questions, by clicking a link and having a new text box and dropdown appear, as items on the list.

I haven't found a really clean way to do that, so I'm sort of piecing it together from various tutorials. Is there a better approach I'm missing?

Here's the code for edit.html.erb:

<h1>Editing Survey: <%= "#{@survey.name}" -%></h1>

<% form_for @survey, :url => {:action => 'update', :id => params[:id]} do |survey_form| %>
  <h2>Title: <%= survey_form.text_field :name %></h2>
  <ol class='question_list'>
  <% for @question in @survey.questions %>
    <% fields_for "question[]" do |f| %>
      <li>
      <%= f.text_field :q_text %><br>
      <%= select(:question, :q_type, { "True/False" => "T", "Multiple Choice" => "M"}) %><br>
      </li>
    <% end %>
  <% end %>
  </ol>
  <%=
    link_to_function "Add another question",
                     update_page {  |page|
                        page.insert_html :bottom, 
                        'blank_question', 
                        (r开发者_如何学运维ender :partial => 'blank_question', :object => @question ) 
                     }

  %>
  <%= submit_tag "Update" %><br>
<% end %> <% "End of form_for" %>

<%= link_to "Back", {:action => 'list' } %>

I created another erb file called _blank_question.erb, which is the elements I would like to have included when they click on the "Add another question" link:

<li>
  <%= text_field :question, :id, :size => 25 %><br>
  <%= select(:question, :q_type, { "True/False" => "T", "Multiple Choice" => "M"}) %><br>
</li>

The problem is that I get the following error in a popup when I click on the "Add another question" link.

RJS error:

TypeError: Object function Element() { [native code] } has no method 'insert'[native code] } has no method 'insert'

Quite a bit of googling hasn't turned up any helpful results. Any idea where I'm going wrong here?


If you are using Rails version > 2.3 (which I recommend if you don't), you can watch two screencasts:

  • Nested Model Form Part 1
  • Nested Model Form Part 2

that explain exactly what you want to do. The second part deals with the Ajax part, but I really recommend watching both the first and the second parts, because Ryan Bates builds this gradually and it will really help you clarify a lot of things.

Generally, the Railscasts site is one of the best ways to learn about a lot of simple or complex Rails stuff.


Some hints:

There seems to be no element 'blank_question' where the rendered HTML could be inserted. You may want to insert into a parent element:

update_page do |page|
  page['parent'].insert_html :bottom, :partial => 'blank_question',
                                      :object => @survey.questions.build
end

Or even simpler let Rails decide which partial to use:

update_page {|page| page['parent'].insert_html :bottom, @survey.questions.build }

This will try to use "_question.html.erb" passing an empty question already associated with your survey as local variable "question", plus you can share partials for rendering existing and new questions (see below).

BTW: See how you can directly skip the call to render (and let Rails build the empty question for your survey).

Another BTW: You can pass the collection to fields_for like so (and it will automatically loop over it and you can skip the for loop):

survey_form.fields_for :questions do |f|
  #...
end

However, this only works if your class Survey; has_many :questions. But this is probably the case. fields_for used on the parent form also supports new objects not yet in the database - this may be of use for you (aka "blank_question"). Also, you can just use form_for @survey do |survey_form|. Rails will be smart enough to use update or create URLs depending on the object being in the database or not. Rails uses the new_record? method for this.

Addendum to the above - to share partials then use:

survey_form.fields_for :questions {|f| render f.object }

This will render "_question.html.erb" for each collection member.

I typically use a helper to render such nested forms:

module SurveysHelper
  def setup_survey(s)
    # add empty question to survey if none associated
    s.questions.build unless s.questions.size > 0
    return s
  end
end

and in the view:

form_for setup_survey(@survey) do |survey|
  survey.fields_for :questions {|f| render f.object }
end


Make sure that prototype.js is included in your rails' javascript directory and that you are importing it in your header:

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜