简体   繁体   中英

Rails Nested Resources - create and edit 2 levels away with form_for in partial

Really racking my brain on this one. I'm relatively new to Rails and trying to do something that I'm sure is not too difficult.

I have a model "Trip" which has many "Days" which has many "Activities"

I am in the show.html.erb view of "Trip" and in this view, I am rendering a partial for a form that should allow me to create a new "Activity" to be associated with a "Day" or edit an existing "Activity" which already belongs to a "Day"

How do I pass to the form_for in the form partial, the local variable of which "Day" I want to create the new "Activity" for. And using that same form partial, how can I retrieve the "Day" that the "Activity" is associated with? Eventually these will be AJAX loaded objects. I've googled for the past several hours and can't find any examples similar to this. I really appreciate the help.

routes.rb

  resources :trips do
    resources :days    
  end

  resources :days do
    resources :activities
  end 

show.html.erb for the Trip

<div id="activities_list">
  <%= render :partial => "activities" %>
</div> 

<div id="activity_form">
  <%= render :partial => "/activities/form", :locals => { :activity => @activity}  %>
</div>

<div id="bottom">
<%= link_to 'Edit', edit_trip_path(@trip) %> |
<%= link_to 'Back', trips_path %>
</div>

_activities.html.erb partial

<h1><%= @trip.title %></h1>

<% @trip.days.each do |day| %>
<div id="blech_<%= day.id %>">
  <b><%= day.summary %></b>
      <% day.activities.each do |activity| %>
            <li id="activity_<%= activity.id %>"><%= link_to activity.address, edit_day_activity_path(day, activity), :remote => true  %></li>
      <% end %>
    <% end %>
  <%= link_to 'New Activity', new_day_activity_path(day), :remote => true %>
</div>
<% end %>

_form.html.erb partial I know that I need to be calling the day_activity_path with (@day,@activity) variables. but I don't know how to get the @day variable in here

  <%= form_for([@activity], :remote => true) do |f| %>
     <fieldset>
       <%= f.label :title, "Activity" %><br />
       <%= f.text_field :title, :rows => 1 %><br />
     </fieldset>

    <div class="actions">
      <%= f.submit %>
    </div>
  <% end %>

ok lets say you want to add a new activity to a day.

do not forget that we are using REST here so (http://old.thoughtsincomputation.com/posts/understanding-rest-in-rails-3)

our day must have many activities and our activity belongs_to a day

class Day < ActiveRecord::Base
  has_many :activities
end

class Activity < ActiveRecord::Base
  belongs_to :day
end

our routes should me something like

resources :days do
  resources :activities
end

with that routes the generated paths we have is something like

days_path
day_path
new_day_path

new_day_activity_path
delete_day_activity_path
edit_day_activity_path

in our day view we are in a url like localhost:3000/days/1 (DaysController, action show)

in wich case we can add a @activity = Activity.new and in a partial add the form below

<%= form_for [@day, @activity] do |form_field| %>
  rest_code_goes_here
<% end %>

this form will submit in ActivityController, action :create with the day and the controller will check for validation and save it .

take a look at the link is a small app i have used something like that https://github.com/leftis/tefteraki/blob/master/app/views/debts/_new_dose.haml

Oh that actualy means that trip have many days and the resouces have more nesting something like

resources :trips
  resources :days
    resources :activities
  end
end

so when you are in local/trips/1/ you actually are in TripController, show action you cannot do it without creating a day texhnicaly you can have a form for the day in which you can use nested form for activities.

the easy way is the gem of ryan bates https://github.com/ryanb/nested_form but to do that you must first change your relations from habtm to

class Day
  has_many :activities
end

class Activity
  belongs_to :day
end

then you will add a day form inside you trip show view

<% nested_form_for [:trip, Day.new], :remote => true do |form| %>

  <%= form.text_field :date %>

  <%= form.fields_for :activities do |activity_form| %>
    <%= activity_form.text_field :name %>
    <%= activity_form.link_to_remove "Remove this activity" %>
  <% end %>
  <p><%= form.link_to_add "Add an activity", :tasks %></p>

<% end %>

the form now makes a request to DaysController.create with params for the trip and the activities and asking to be served ajaxly

check at gem and my app i am using all of this i hope it helps!!!

This is what I ended up doing and it works.

In my show.html.erb for my "Trip".

show.html.erb

<div id="activity_form">
<h2>Activities</h2>
</div> 

link to "Edit' an Activity. Notice the :remote => true which tells the Rails controller that this will be an AJAX request so to render edit.js.erb

<%= link_to activity.location[0, 20], edit_day_activity_path(day, activity), :class=>"btn btn-info fixedwidthbtn", method: :get, :remote => true 

_form.html.erb This form partial is under the Activities View directory (../views/activities/_form.html.erb).

<%= form_for([@day, @activity], :remote => true) do |f| %>
<fieldset>
  <%= f.label :title, "Activity" %>
  <%= f.text_field :title, :rows => 1 %> 
</fieldset>
  <div class="actions">
    <%= f.submit %>
  </div>
</form>
   <%= link_to 'Delete', [@day, @activity], method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>

edit.js.erb This is a file under the Activities view directory (../views/activities/edit.js.erb). Says to grab the DOM element with ID of "activity_form" and render the partial "form"

$("#activity_form").html("<%= escape_javascript(render(:partial => "form"))%>");

update.js.erb I included this javascript after hitting update on the Edit form to render an updated partial of the Activities List. So that I don't have to reload the page to see an update.

$("#activities_list").html("<%= escape_javascript( render(:partial => "/trips/activities") ) %>");

routes.rb This is how I nest my routes. Only doing it 1 level following best practices.

resources :trips do resources :days end

resources :days do resources :activities end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM