I have the below form working as a partial, i'm trying to do a partial call for a Contractors models and i want to also pass the current page's model id which is a quote id.
Its failing on this line <%= hidden_field_tag :quote_id, #quote.id %> 'called id for nil'
I've tried creating a manual route and putting the search on a seperate method, but then i get a template error so i'm just leaving it in the index method for now.
Form in show.html.erb:
<%= form_tag quotes_path, :method => 'get', :id => "contractors_search" do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<br><br><br>
<div id="contractors"><%= render 'contractors' %></div>
<% end %>
_contractors.html.erb
<table>
<% #contractors.each do | contractor | %>
<tr>
<td><%= contractor.firstname %></td>
<td>
<%= form_tag (quote_add_contractor_path) do %>
<%= hidden_field_tag :quote_id, #quote.id %>
<%= hidden_field_tag :contractor_id, contractor.id %>
<%= submit_tag "Add" %>
<% end %>
</td>
</tr>
<% end %>
</table>
Index.js.erb
$("#contractors").html("<%= escape_javascript(render :partial => "contractors") %>");
Controller:
def index
#quotes = Quote.all
#contractors = Contractor.search(params[:search])
end
def add_contractor
#quote = Quote.find(params[:quote_id])
#contractor = Contractor.find(params[:contractor_id])
#quote.contractors << #contractor
if #quote.save
redirect_to #quote, notice: "contractor was added"
else
render :show, notice: "Sorry, something went aweful"
end
end
In index.js.erb you render the partial contractors but you do not set the #quote instance variable in your index action of the controller. That is why you are getting this failure. Try to add #quote = # Some logic here to your index action.
Related
I'm not getting it. I'm building a rails application and want to do some single page actions. What I got from now is, when a I pick a 'customer' from the list on the customers/index.html.erb, I render it in the 'current_customer' div. When I click on edit, the form is rendered in the 'current_customer' - perfect. But when I click on sumbit on the form, I get an error (which I understand) 'ActionController::UnknownFormat' because of the action oin the controller for 'show'. I'm routed to 'http://localhost:3000/customers/2'
What I want to is to route to 'http://localhost:3000/customers' after clikcing sumit and the render the cutomers/_show.html.erb in the 'current_customer' div.
My Code:
customers/index.html.erb
<h1>Listing Customers</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th colspan="3">Actions</th>
</tr>
</thead>
<tbody>
<% #customers.each do |customer| %>
<tr>
<td><%= customer.name %></td>
<td><%= link_to 'Show', customer, remote: true %></td>
<td><%= link_to 'Edit', edit_customer_path(customer), remote: true %></td>
<td><%= link_to 'Destroy', customer, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<div id="current_customer"></div>
<br>
<%= link_to 'New Customer', new_customer_path, class: "button", id: "new_customer" %>
customers/_show.html.erb
<p>
<strong>Name:</strong>
<%= #customer.name %>
<%= #customer.id %>
</p>
<%= link_to 'Edit Customer', edit_customer_path(#customer) %> |
customers/_edit.html.erb
<h1>Editing Customer</h1>
<%= render 'form' %>
<%= link_to 'Show', #customer %> |
customers/_form.html.erb
<%= form_for(#customer) do |f| %>
<% if #customer.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#customer.errors.count, "error") %> prohibited this customer from being saved:</h2>
<ul>
<% #customer.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="actions">
<%= f.submit id: "customer_button", remote: true %>
</div>
<% end %>
customers/edit.js.erb
$("#current_customer").html("<%= escape_javascript(render partial: 'customers/edit', locals: { customer: #customer } ) %>");
customers_controller.rb (partly)
def show
respond_to do |format|
format.js {render layout: false}
end
end
# GET /customers/new
def new
end
# GET /customers/1/edit
def edit
respond_to do |format|
format.js {render layout: false}
end
end
def update
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to #customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
I'd be glad for every help!
Thanks
You need to put remote: true in form_for tag instead of submit button, add it here
<%= form_for #customer, remote: true do |f| %>
Remove it from
<%= f.submit id: "customer_button" %>
Also, update action should accept AJAX requests too, create update.js.erb template and handle the AJAX request as you are submitting the form using remote: true
Hope that helps!
Submitting you form as is will call POST /customer/1. You need to defined an update method in your controller and routes, and add method: :patch to your form to achieve a PATCH /customer/1.
Also, you might want to defined a update.js.erb and add remote: true to your form to add some dynamic AJAX.
you can replace your show link by this:
<%= link_to "show", {:action => :show}, :remote => true %>
or
<%= link_to "show", customer_path(customer), :remote => true %>
In my _form partial I render another partial like below
<%= render :partial => 'test', :object => #application.type, \
:locals => {:form => form, \
:application_type => "application[type]"} %>
When I try to load the form I get this error
undefined local variable or method `form' for #<#<Class:0x6daf2c8>:0x8dd3c80>
My test partial
<%= fields_for application_type, application do |application_f| %>
<div>
<div>
<%= application_f.label :uni_id, "University" %>
<%= application_f.collection_select :uni_id, #unis, :id, :check, {:include_blank => true} %>
</div>
</div>
<div>
<% end %>
I recently updated to rails 4.1 from 3.2. It was working before but now it shows error. I guess it is syntax error but could not solve it.
Maybe you need to replace something like this, in your top-level template:
<%= render partial: "form", form: form %>
or like this:
<%= render partial: "form", object: form %>
with something like this (the locals parameter is required now)
<%= render partial: "form", locals: { form: form } %>
Quite a few errors:
<%= render partial: 'test', locals: {form: form }, object: #application %>
<%= form.fields_for application.type, application do |application_f| %>
<div>
<div>
<%= application_f.label :uni_id, "University" %>
<%= application_f.collection_select :uni_id, #unis, :id, :check, {:include_blank => true} %>
</div>
</div>
</div>
<% end %>
This should provide the correct syntax for you.
The error is down to the form variable not being populated. This seems to be from the <%= render call. Without context, the best fix I can give is how it should look:
<%= form_for #variable do |form| %>
<%= render partial: "test", locals: {form:form}, object: #application %>
<% end %>
I experienced this same issue when working on a Rails 6 application
I did an overriding of my routes due to some conflicts from
resources :sessions
to
resources :sessions, as: :sets
Here's how I fixed it:
app/views/sessions/new.html.erb
<h1>New Session</h1>
<%= form_with(model: #session, url: sets_path, local: true) do |form| %>
<%= render partial: 'form', session: #session, locals: { form: form } %>
<% end %>
<%= link_to 'Back', sets_path %>
Note: A URL was defined for the New Form since routing override was done. Thus, the form_with container was isolated from the _form.html.erb partial. This is in a bid to avoid creating multiple _form.html.erb partials for the new.html.erb and edit.html.erb files, since they have different URLs.
app/views/sessions/edit.html.erb
<%= form_with(model: #session, url: set_path(#session), local: true) do |form| %>
<%= render partial: 'form', session: #session, locals: { form: form } %>
<% end %>
<%= link_to 'Show', set_path(session) %> |
<%= link_to 'Back', sets_path %>
Note: A URL was defined for the New Form since routing override was done. Thus, the form_with container was isolated from the _form.html.erb partial. This is in a bid to avoid creating multiple _form.html.erb partials for the new.html.erb and edit.html.erb files, since they have different URLs.
app/views/sessions/_form.html.erb
<% if #session.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#session.errors.count, "error") %> prohibited this session from being saved:</h2>
<ul>
<% #session.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :prefix %>
<%= form.text_field :prefix %>
</div>
<div class="actions">
<%= form.submit %>
</div>
Note: Notice that there is no form helper definition in the _form.html.erb file, it was moved to the new.html.erb and edit.html.erb files, since they now have different URLs due to the modification of their route.
app/views/sessions/index.html.erb
<p id="notice"><%= notice %></p>
<h1>Sessions</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Prefix</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #sessions.each do |session| %>
<tr>
<td><%= session.name %></td>
<td><%= session.prefix %></td>
<td><%= link_to 'Show', set_path(session) %></td>
<td><%= link_to 'Edit', edit_set_path(session) %></td>
<td><%= link_to 'Destroy', set_path(session), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Session', new_set_path %>
Note: Pay attention to the modification of the link URLs in the new action.
app/views/sessions/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #session.name %>
</p>
<p>
<strong>Prefix:</strong>
<%= #session.prefix %>
</p>
<%= link_to 'Edit', edit_session_path(#session) %> |
<%= link_to 'Back', sessions_path %>
Note: Pay attention to the modification of the link URLs in the edit and back actions.
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
before_action :set_session, only: [:show, :edit, :update, :destroy]
# GET /sessions
# GET /sessions.json
def index
#sessions = Session.all
end
# GET /sessions/1
# GET /sessions/1.json
def show
end
# GET /sessions/new
def new
#session = Session.new
end
# GET /sessions/1/edit
def edit
end
# POST /sessions
# POST /sessions.json
def create
#session = Session.new(session_params)
respond_to do |format|
if #session.save
format.html { redirect_to sets_path(#sesion), notice: 'Session was successfully created.' }
format.json { render :show, status: :created, location: sets_path(#sesion) }
else
format.html { render :new }
format.json { render json: #session.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /sessions/1
# PATCH/PUT /sessions/1.json
def update
respond_to do |format|
if #session.update(session_params)
format.html { redirect_to sets_path(#sesion), notice: 'Session was successfully updated.' }
format.json { render :show, status: :ok, location: sets_path(#sesion) }
else
format.html { render :edit }
format.json { render json: #session.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sessions/1
# DELETE /sessions/1.json
def destroy
#session.destroy
respond_to do |format|
format.html { redirect_to sets_url, notice: 'Session was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_session
#session = Session.find(params[:id])
end
# Only allow a list of trusted parameters through.
def session_params
params.require(:session).permit(:name, :prefix)
end
end
Note: Pay attention to the modification of the redirect URLs in the create and update actions.
That's all.
I hope this helps
I would like to display every files that belong to one given project (the relationship works fine, could check it using the Rails console).
Here is my 'Project' controller , I may need a do loop (to loop through each files , for 1 project) but I'm not sure :
def show
#project = Project.find(params[:id])
#pfile = Project.find(params[:id]).Pfiles.find(:all)
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #project }
format.xml { render :xml => #pfile }
end
end
This is my 'Project' view :
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #project.name %>
</p>
<p>
<b>Description:</b>
<%= #project.description %>
</p>
<p>
<b>Files:</b>
<%= #project.pfile.name %>
</p>
<%= link_to 'Edit', edit_project_path(#project) %> |
<%= link_to 'Back', projects_path %>
Thanks :)
If the relationship is set up correctly you can do this:
controller
#pfiles = #project.pfiles
view
<p>
<b>Files:</b>
<% #pfiles.each do |pfile| %>
<%= pfile.name %>
<% end %>
</p>
easier yet... rely on the magic of rails.
in the controller
#project = Project.find(params[:id])
#pfiles = #project.pfiles
then in the view
<b>Files:</b>
<%= render #pfiles %>
then in views/pfiles/_pfile.html.erb
<%= pfile.name %>
Sorry about the repetition, I could not find the answers to my questions after a lot of searches. The will_paginate does not work after the Ajax call.
After delete action, It does not display the pages numbers at all (it simply returns all results).
After search action, the page number does not update, it shows more pages than what should actually be there.
Here is the controller code.
class CitiesController < ApplicationController
def index
#cities = City.get_cities(params[:city_name],params[:city_population]).paginate(:page => params[:page])
respond_to do |format|
format.html
format.js
end
end
def create
#city = City.new(params[:city])
if #city.save
flash[:success] = "City information saved successfully"
redirect_to cities_path
else
render 'index'
end
end
def new
#city = City.new
end
def destroy
#city = City.find(params[:id]).destroy
#city.destroy
#cities = City.all
respond_to do |format|
format.html {redirect_to cities_path}
format.js
end
end
end
Here is the index view:
<div class="row">
<h1>Search Cities or <%= link_to "Create New City", new_city_path %></h1>
<h3>99 random city information are generated in the database </h2>
<h3>Simply type any letter or city population between 0 and 10 to filter out</h3>
<%= form_tag "/cities/index", method: :get, remote: true do %>
<%= label_tag(:q, "City Name:") %>
<%= text_field_tag 'city_name' %>
<%= label_tag(:q, "City Population greater than, in units of 1 million:") %>
<%= text_field_tag 'city_population' %>
<label></label>
<%= button_tag("Search", :class => "btn") %>
<% end %>
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %>"><%= value %></div>
<% end %>
<div id='table' class="table table-striped">
<%= render 'table' %>
</div>
<%=will_paginate #cities %>
</div>
Here is the partial view of the table:
<div class="row">
<h1>Enter City descriptions or <%= link_to "Search Cities", cities_path %></h1>
<%= form_for #city, html: {multipart: true} do |f| %>
<%= f.label :city_name %>
<%= f.text_field :city_name %>
<%= f.label :city_description %>
<%= f.text_field :city_description %>
<%= f.label :city_population_in_units_of_millions %>
<%= f.text_field :city_population %>
<label></label>
<%= f.file_field :image%>
<label></label>
<%= f.submit "Create new City", :class => "btn"%>
<% end %>
</div>
Finally two js.erb codes associated with index and delete actions:
index.js.erb:
$('#table').html('<%= escape_javascript(render('table')) %>');
destroy.js.erb:
$('#table').html('<%= escape_javascript(render('table')) %>');
Found the solution by myself.
add <%= will_paginate #cities %> into partial file
and change #cities = City.all to
#cities = City.all.paginate(page: params[:page])
because will_paginate does not expect an array of objects.
write in your controller
def index
#cities = City.get_cities(params[:city_name],params[:city_population]).paginate(:page => params[:page])
respond_to do |format|
format.html
format.js
end
end
in your view folder create index.js.erb and write
$('id or class').html('<%=escape_javascript render :partial => which part you update %>')
This is really simple, but i'm going slightly mad and probably missing something that's staring me in the face. Can anyone help?
Basically, I have a simple each loop that's returning an extra rogue line. Even when there's nothing in the db, I get one line returned!
My show view including the loop is:
<p id="notice"><%= notice %></p>
<p>
<b>Header:</b>
<%= #mailer.header %>
</p>
<p>
<b>Subtext:</b>
<%= #mailer.subtext %>
</p>
<div id="" class="" padding-left: 30px;>
<h3>Mailer Products </h3>
<ol id="mailer-Product-list">
<% #mailer.mailer_products.sort_by { |mailer_products| mailer_products.position }.each do |mailer_product| %>
<%= content_tag_for :li, mailer_product do %>
<%= mailer_product.product.cat_no %>
<% end %>
<% end %>
</ol>
<%#= link_to 'Done', #product, :class => "standard-button" %>
</div>
<%= form_for([#mailer,#mailer.mailer_products.build]) do |f| %>
<div class="field">
<%= f.label :product_id %><br />
<%= f.text_field :product_id %>
</div>
<div class="field">
<%= f.hidden_field :mailer_id, :value => #mailer.id %>
</div>
<div class="actions">
<%= f.submit "Add Product" %>
</div>
<% end %>
<%= link_to 'Edit', edit_mailer_path(#mailer) %> |
<%= link_to 'Back', mailers_path %>
The controller code is:
class MailersController < ApplicationController
def show
#mailer = Mailer.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #mailer }
end
end
class MailerProductsController < ApplicationController
def index
#mailer_products = MailerProduct.find(:all)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #mailer_products }
end
end
end
end
Your call to form_for looks like this
form_for([#mailer,#mailer.mailer_products.build]) do |f|
You get an extra blank item because that's what calling .build on mailer_products does: it appends a new instance to the array
When the form is after the loop this doesn't matter, but when things are the other way around the loop will be on the modified array
My usual mistake is adding a <%= instead of a <% on the loop...
<%= #foo.each do |itme| %>
# do stuff
<% end %>
which should be
<% #foo.each do |itme| %>
# do stuff
<% end %>
Double check your tags...