rails ajax requested form has wrong method - ruby-on-rails

I have a _form.html.erb partial that comes from the standard rails 3 template for the model project.
#view:
<div id="content">
<%= link_to 'Edit', edit_project_path(#project), :remote => :true %>
</div>
#projects controllers
def edit
#project = Project.find(params[:id])
respond_to do |format|
format.html # edit.html.erb
format.js { render "form.js.rjs" }
end
end
#form.js.rjs
page.replace_html "content", :partial => 'form'
#_form.html.erb
<%= form_for(#project) do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% #project.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
While i click that link to edit a project, the form does come through through ajax, but the method for the form is now post instead of put. which means as i submit, it will create new projects with the same attributes as the existing one that I am editing b/c of the create method that's called upon receiving a post request.
I know that form_for(#project) rely on record id to tell whether it's new or not, I looked through all the sources for form_for, form_tag, extras_tags_for_form, form_tag_html but cannot find a place where they specify which method for the form tag is to be used. The closest place where it defines the method is in extra_tags_for_form, but in that method, it is merely sieving through the :method option hash that's already passed to it, but from where is this :method option passed? I cannot find.
any ideas?

You are on the right track, form_form(obj) will look at the objects dirty flag to figure out what to do with it. That doesn't mean you can't tell it what to do though :)
form_for actually has a few hashes in its optional params, :method lives inside :html. so to force it to be put, just do something like this
form_for #project, :html => {:method => :put} do |f|

Related

Rails: Add form from different model

In my rails app, i have a project model which can have many project messages.
project has_many project_messages
In projects/show.html.erb, I would like to display all project messages for that project but also create new project messages from this view.
Currently, I am not able to create new project messages from this view.
I have reviewed a number of links but none work for me
Adding Form For Different Model In Same View,
Rails: Show form from different model in a view
My projects/show.html.erb file references as follows:
<div>
<% render partial: 'project_messages/form', :object => #project_message %>
</div>
In the projects_controller.rb file I have included the following:
def show
#project_message = ProjectMessage.new
end
&
def project_params
params.require(:project).permit(:title, :description, :phase_id, :RAGStatus, :currentpphase_id, :project_messages_attributes => [:pMessage, :user_id, :project_id])
end
And in the project.rb file I have the following code also:
accepts_nested_attributes_for :project_messages
project_messages/_form.html.erb
<%= form_with(model: project_message, local: true) do |form| %>
<% if project_message.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(project_message.errors.count, "error") %> prohibited this project_message from being saved:</h2>
<ul>
<% project_message.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form.label :pMessage %>
<%= form.text_field :pMessage, id: :project_message_pMessage, :class => 'au-input au-input--full au-input--h65', placeholder: 'Type a message' %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
The project_messages form partial does not render so I cannot add a new message from this view.
Error:
undefined local variable or method `project_message' for #<#<Class:0x007f5455ced910>:0x007f5459ef8a30>
Did you mean? #project_message
When I add #project_message to the partial, it does not render.
Normally, when rendering a partial like:
<% render partial: 'form', object: #project_message %>
Because you are passing the #project_message as the specially-named object parameter, this creates a special variable with the name of the partial - in this case, form.
Therefore in the partial, you could reference this variable:
<%= form_with(model: form, local: true) do |form| %>
...However, in this case, it doesn't really make sense to call the local variable form! So I would be inclined to use whatever name you're passing it in as - for example, you could do:
<% render partial: 'form', project_message: #project_message %>
And then in the partial:
<%= form_with(model: project_message, local: true) do |form| %>
For more info, see: http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
In project_messages/_form.html.erb, this line:
<%= form_with(model: project_message, local: true) do |form| %>
Should be changed to this:
<%= form_with(model: object, local: true) do |form| %>
You assigned a local variable object to a partial, so you should use it.
Also, partials may also be called this way:
<% render partial: 'form', object: #project_message %>

Ruby On Rails - creating an object does not respect validations and showing error messages

I'm having troubles handling objects that not respect the validation.
I'm building an app in which an user can create a "Trip" model and then add steps to his trip, that I called "Traces". Each added trace prints a new part of a map present in the trip#show action.
The association between models is user has_many trips and trip has_many traces
In the users#show I put a "CREATE NEW TRIP" button linking to the trips#new and here I have the form_for with the field corresponding to the Trip attributes.
When I fill the form correctly everything is ok. When something is missing or wrong (for the validations) I get this error:
NoMethodError in Trips#create
undefined method `model_name' for Array:Class
------ in the trips_controller.rb
def create
#trip = current_user.trips.build(params[:trip])
if #trip.save
# handle a successful save
flash[:success] = 'Trip created!'
redirect_to user_trip_path(#trip, user_id: current_user.id)
else
#trip = []
#feed_items = []
render 'new'
end
end
------ in app/views/trip, in the new.html.erb
h1>Create a trip</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3 general-input">
<%= form_for ([current_user, #trip]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name,'Give a name to your trip ;)' %>
<%= f.text_field :name %>
<%= f.label :trip_start, 'Choose your starting point!' %>
<%= f.text_field :trip_start %>
<%= f.label :departure, 'When are you leaving?' %>
<%= f.date_select :departure, :start_year => Date.current.year %>
<%= f.label :arrive, 'And coming back home?' %>
<%= f.date_select :arrive, :start_year => Date.current.year %>
<%= f.submit 'Create a new trip', class: 'btn btn-primary btn-lg' %>
<% end %>
EDIT 1: problem solving removing #trace=[ ] from trips_controller.rb
EDIT 2:
I also have a similar problem with the creation of a new Trace:
The form for adding a new trace is in the trip#show page.
When I try to create a trace that not respects the validation (e.g. if I leave blank the "destination" field) I get this error:
NoMethodError in Posts#create
undefined method `any?' for nil:NilClass
When I'm on the Trip page where the form for the Traces is placed, the URL is like:
http://localhost:3000/users/2/trips/8
but when I create a not valide Trace it switchs to a path like:
http://localhost:3000/trips/8/posts
I suppose I'm doing something wrong handling the error messages. I probably misunderstood something, even because I'm new to Rails and web programming in general.
Here you are some code parts, hoping it helps to understand my mistake:
------ in the traces_controller.rb
def create
#trip= Trip.find(params[:trip_id])
#trace = #trip.traces.create(params[:trace])
if #trace.save
flash[:success] = 'Trace created!'
redirect_to user_trip_path(#trip, user_id: current_user.id)
else
#trace=[]
render 'trips/show'
end
end
------ in app/views/shared, in the add_trace_form.html.erb
<p>Complete your trip adding a route!</p>
<%= form_for ([#trip, #trip.traces.build]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="block post-form">
<div class="field ">
<%= f.text_field :end, placeholder: 'Where are you going next?' %>
<%= f.label :arr_day, 'When?' %>
<%= f.date_select :arr_day, :start_year => Date.current.year %>
<%= f.submit 'Add route', class: 'btn btn-primary btn-landing' %>
</div>
</div>
<% end %>
------ in app/views/shared, in the error_messages.html.erb
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |message| %>
<li>* <%= message %></li>
<% end %>
</ul>
</div>
<% end %>
------ in the routes.rb
resources :users do
resources :trips
end
resources :trips do
resources :traces
end
resources :traces
Thanks a lot
i think when you are passing the f.object in locales in render its is passing array not the active record object ,<%= render 'shared/error_messages', object: f.object %>.
Can u check inspecting object in your partial and what class it has.
Try inspecting object.errors.inspect
Try refering http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials

How to redirect_to(:back) two times?

def update
if #note.update_attributes(note_params)
redirect_to :back, notice: "Note was updated."
else
render :edit
end
end
Is there a way to redirect back twice?
Here you go:
This is where the link for editing goes:
<p id="notice"><%= notice %></p>
<% url = "#{request.protocol}#{request.host_with_port}#{request.fullpath}" %>
<%= link_to 'Create New Page and Return Here', edit_page_path(1, :url => Base64.encode64(url) ) %>
<br>
After submit your url will be something like this:
http://localhost:3000/pages/1/edit?url=aHR0cDovL2xvY2FsaG9zdDozMDAwL2R1bW1pZXM%3D%0A
In the edit form:
I called it pages/_form.html.erb, Pass the URL as a hidden params.
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this page from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :permalink %><br>
<%= f.text_field :permalink %>
</div>
<%= hidden_field_tag :url, params[:url].to_s %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In controller that you have update method, in this case pages_controller.rb, simply Base64 it back and redirect the user:
def update
redirection = nil
if params[:url].present?
redirection = Base64.decode64(params[:url].to_s)
end
if #page.update(page_params)
if redirection.present?
path = redirection
else
path = #page
end
redirect_to path, notice: 'All Done.'
else
render :edit
end
end
Now user updates the form and redirected back to the first show or index page or any page that she is coming from.
Hope this help.
PS: You might want to clean it up a bit and pass the url from the controller, and put some checks on it. So you don't define any var at the view level. In the above code I just tried to solve this issue not really a design pattern oriented :)

Submit a form to a model from my homepage

I have a links model which has all the generic scaffold created for it, however, rather than go to the link#new page, I'd like to submit a form from my homepage that populates a new record.
I only have one text field, but im not sure how to construct the form. I read somewhere you have to specify the controller in the form field but this doesn't appear to be working.
<%= form_for(:link, #link) do |f| %>
<% if #link.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#link.errors.count, "error") %> prohibited this link from being saved:</h2>
<ul>
<% #link.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :url %><br />
<%= f.text_field :url %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You don't need to specify anything if you are using default routes.
If the #link is an object that doesn't exist in database, Rails will automatically think this is a form for #new. So the form action will be /links, and method is post, which is the default resource to #create
In your case, you don't need to do anything, just revise the form code to:
<%= form_for(#link) do |f| %>
....
Besides, you need to prepare #link object in home controller, something like
#link = Link.new
All you have to do is add a url parameter to the form_for helper
<%= form_for :link, url: your_home_path do |f| %>

How to render a "Edit" form partial in the "Show" page of another model in Rails

I want to display an "Edit" form in the "Show" view of a parent object.
My model looks like this:
A Trip has many Days which has many Activities.
Trip accepts nested attributes for Days. Days accepts nested Attributes for Activities.
When I am in the "Show" view for a Trip, how do I render an "Edit" form partial for an "Activity"?
I know I need to somehow specify to the Edit Form partial which Activity ID that I want to edit but I'm not sure how to pass along that information from the "Show" view of a "Trip".
<% #trip.days.each do |day| %>
<div id="daydiv_<%= day.id %>">
<b><%= day.summary %></b>
<%= content_tag_for :ol, day do %>
<% day.activities.each do |activity| %>
<li id="activity_<%= activity.id %>"><%= link_to activity.address, edit_activity_path(activity) %></li>
<% end %>
<% end %>
</div>
<% end %>
<div id="activity_form">
<%= render :partial => "/activities/form", :activity => #activity %>
</div>
my /activities/form partial looks like this:
<%= form_for(#activity) do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
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

Resources