I've searched this site and asked a couple other programmers and can't figure out what the problem is with my code. I'm a beginner to Rails, so I'm still trying to figure everything out.
I'm getting this error:
ActionController::UrlGenerationError in Lists#show
No route matches {:action=>"toggle_completed", :controller=>"tasks", :id=>nil, :list_id=>3} missing required keys: [:id]
Here is the code it's referring to on the Lists#show page:
<p id="notice"><%= notice %></p>
<h3>add a task</h3>
<%= render 'tasks/form', task: Task.new() %>
<p>
<strong>List Name:</strong>
<%= #list.name %><p></p>
<% #list.tasks.each do |task| %>
<td><%= task.id %></td>
<td><%= task.name %></td>
<td><%= task.completed %></td>
<td><%= link_to('Toggle', toggle_completed_list_task_path(:list_id => #list.id,
:id => task.id), :method => :put ) %></td><br />
<% end %>
</p>
My Routes:
resources :lists do
resources :tasks do
member do
put :toggle_completed
end
end
end
Tasks Controller:
def toggle_completed
#task = Task.find(params[:id])
#task.completed = !#task.completed
#task.save
end
List has_many: tasks
and
Task belongs_to: list
I've experimented a bit and on my Lists#show page, if I add this line:
<%= task.id %>
The correct value appears on the page, so I'm not sure why it's coming up nil. I've searched the site and haven't found anything that really discusses this exact issue. Thanks!
create a separate routes for toggle_completed ex-
put 'list/task/:id', to: 'tasks#toggle_completed', as: :list_task_completed
and
<%= link_to('Toggle', list_task_completed_path(:id => task.id), :method => :put ) %>
Related
My application needs to duplicate a Skill (from skills index) as many times the user needs it in his cart. So I decided to trigger the add-to-cart method of the skills_controller when the related form, including the number of duplicates and the Skill's id, is submitted. For this purpose, I added counter to the strong parameters of skills_controller.
Unfortunately, I am missing something to correctly setup the form: when submitted, it triggers the create method. Here is the code:
routes.rb extract
resources :skills, :path => "variables" do
resources :values_lists
member do
post :add_to_cart
get :create_values_list
get :upload_values_list
get :remove_values_list
end
collection do
get :index_all
end
end
skills_controller.rb method
def add_to_cart
#template_skill = Skill.find(params[:id])
iterations = params[:skill][:counter].to_i
until iterations == 0
#skill = #template_skill.deep_clone include: [:translations, :values_lists]
#skill.business_object_id = session[:cart_id]
#skill.template_skill_id = #template_skill.id
#skill.code = "#{#template_skill.code}-#{Time.now.strftime("%Y%m%d:%H%M%S")}-#{iterations}"
#skill.is_template = false
#skill.save
iterations -= 1
end
#business_object = BusinessObject.find(session[:cart_id])
redirect_to #business_object, notice: t('SkillAdded2BO') # 'Skill successfully added to business object'
end
index.html.erb table content
<tbody>
<% #skills.each do |skill| %>
<tr data-href="<%= url_for skill %>">
<% if not session[:cart_id].nil? %>
<td>
<%= form_with model: #skill, :action => "add_to_cart", :method => :post, remote: false do |f| %>
<%= f.text_field :counter, value: "1", class: "mat-input-element", autofocus: true %>
<button type="submit" class="mat-icon-button mat-button-base mat-primary add-button" title="<%= t('AddToUsed') %>">
<span class="fa fa-plus"></span>
</button>
<% end %>
</td>
<% end %>
<td class="no-wrap"><%= skill.code %></td>
<td><%= link_to skill.translated_name, skill %></td>
<td><%= link_to translation_for(skill.parent.name_translations), skill.parent %></td>
<td><%= skill.responsible.name %></td>
<td><%= skill.updated_by %></td>
<td class="text-right"><%= format_date(skill.updated_at) %></td>
</tr>
<% end %>
</tbody>
Thanks a lot for your help!
According to this form helpers guide, the syntax you used doesn't exist
form_with model: #model, action: :custom_action
So in this case, you have to specify the url parameter for form_with to make it works.
<%= form_with model: #skill, url: :add_to_cart_skill_path(#skill), method: :post, remote: false do |f| %>
I'm trying to pass parameters using link_to with ruby on rails, but it says the id parameter I'm sending is null.
code from where I'm sending the id.
<% #conference.papers.each do |paper| %>
<tr>
<td><%= paper.title %></td>
<td><%= paper.author %></td>
<td><%= link_to "Download Paper", paper.attachment_url %></td>
<td><%= link_to 'Reviews', paper %></td>
<% if (paper.accepted) %>
<td><%= "Accepted" %></td>
<% else %>
<td><%= "Not accepted" %></td>
<% end %>
<% if (#state1 && paper.accepted == false) %>
<td><%= button_to "Accept", accept_paper_path(id: paper.id), class: "btn btn-danger", data: { confirm: "Are you sure that you wish to accept #{paper.title}?"} %></td>
<% end %>
<% if (#state2) %>
<% session["a"] = paper.id %>
<td><%= link_to "Review paper", new_review_path(id: paper) %></td>
<% end %>
</tr>
<% end %>
code for the review controller
def new
#paper = Paper.find_by_id(params[:id])
#review = Review.new()
end
You missed .id in
link_to "Review paper", new_review_path(id: paper.id)
But it is not a good solution. If your Paper model has_many :reviews, it would be better to nest reviews routes in paper's ones. Like this:
# config/routes.rb
resources :papers do
resources :reviews
end
And so, your link_to will look like:
link_to "Review paper", new_paper_review_path(paper)
which will generate
/papers/:paper_id/reviews/new
You can learn more about Rails routing here.
Lets start by setting up the routes properly:
resouces :papers do
member do
patch :accept
end
end
This will let you accept a review by PATCH /papers/:id. To create the button use:
<%= button_to accept_paper_path(paper), method: :patch %>
Note that this should use the PATCH or PUT http method - not GET since it is a non-idempotent action.
Note that you can just pass the model instead of doing accept_paper_path(id: model) or accept_paper_path(id: model.id).
For reviews you will want to create what is called a nested resource:
resouces :papers do
member do
patch :accept
end
resources :reviews, only: [:new, :create]
end
This gives you the route /papers/:paper_id/reviews/new.
<%= link_to "Review paper", new_paper_review_path(paper) %>
To set the form to create a new review to the use correct path use an array containing the parent and child:
<%= form_for([#paper, #review]) %>
I'd like to learn how to use the methods defined in the controller in the index page.
I'm trying to implement "like" button on my blog.
PostController
def like
#post = Post.find(params[:id])
#post.like += 1
#post.save
end
In the index where all the posts are listed, I tried something like this.
<% #posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= post.created_at.strftime("%Y/%m/%d, %I:%M%p") %></td>
<td><%= post.view %></td>
<td><%= link_to 'like', like_post_path %></td>
<td>hate</td>
</tr>
<% end %>
I got the idea by looking at the code,
<%= link_to 'make a new post', new_post_path %>
<%= link_to 'Edit', edit_post_path(post) %>
I thought the way to use methods in the controller in the index page was
(method in PostController)_post_path, but it seems I got it wrong.
undefined local variable or method `like_post_path'
I've also tried like(post).
My ultimate goal is to make this function as an ajax function, so I expected it to be a form like
<% link_to_function 'like', like_post, remote: true %>
What's the right way of using the method "like" in this case?
You'd need to define a named route to make this work. Like:
# in config/routes.rb
resources :posts do
member do
get 'like'
end
# OR
get 'like', :on => :member
end
# in `rake routes` this would show up as:
like_post GET /posts/:id/like(.:format) posts#like
# you'd reference in a view like:
like_post_path(#post)
I've been digging through routing documentation and seem to have only uncovered half of the necessary info needed for this one.
If I create a route which looks like:
match 'attendances/new/:class_date/:student_id'
I'm afraid I'm completely unclear on how to create an appropriate link_to incantation which is capable of fulfilling the above.
For example, I seem to have no problems creating this URL:
http://localhost:3000/attendances/new?class_date=2012-05-07&student_id=5
but I've yet to find appropriate docs which explains how to create this:
http://localhost:3000/attendances/new/2012-05-07/5
Could someone provide a helpful example and/or a link to docs which discusses how to do this?
I realize that trying to use link_to might be completely inappropriate here. And I realize I could munge together some code which will craft the appropriate links, but I suspect that doing so will completely miss some better, Ruby-on-Rails way to doing this.
Edit: Corrected proposed match route, above.
Edit 2: Going on "mu is too short"'s suggestion, here's what my routes.rb now looks like:
NTA::Application.routes.draw do
resources :students
resources :libraries
resources :year_end_reviews
resources :notes
resources :ranktests
resources :attendances
match 'attendances/new/:class_date/:student_id', :as => :add_attendance
resources :ranks
get "home/index"
root :to => "home#index"
end
and here's the relevant view:
<% today = Date.today %>
<% first_of_month = today.beginning_of_month %>
<% last_of_month = today.end_of_month %>
<% date_a = first_of_month.step(last_of_month, 1).to_a %>
<h2><%= today.strftime("%B %Y") %></h2>
<table id="fixedcolDT">
<thead>
<tr>
<th>Name</th>
<% date_a.each do |d| %>
<th><%= d.day %></th>
<% end %>
</tr>
</thead>
<tbody>
<% #students.each do |s| %>
<tr>
<td><%= s.revfullname %></td>
<% date_a.each do |d| %>
<% student_attend_date = Attendance.find_by_student_id_and_class_date(s.id, d) %>
<% if student_attend_date.nil? %>
<td><%= link_to "--", add_attendance_path(d, s.id) %></td>
<% else %>
<td><%= student_attend_date.class_hours %></td>
<% end %>
<% end %>
</tr>
<% end %>
</tbody>
</table>
and here's what I get back after the initial reload (before trying to restart WEBrick):
ArgumentError
missing :controller
Rails.root: /Users/jim/Documents/rails/NTA.new
Application Trace | Framework Trace | Full Trace
config/routes.rb:15:in `block in <top (required)>'
config/routes.rb:1:in `<top (required)>'
This error occurred while loading the following files:
/Users/jim/Documents/rails/NTA.new/config/routes.rb
I'll pastebin what I got back after my failed attempt to restart WEBrick, if interested.
First of all, you want to give the route a name so that you'll get the appropriate helper methods:
match ':attendances/:new/:class_date/:student_id' => 'controller#method', :as => :route_name
That will generate two methods that you can use to build the URL:
route_name_path: The path for the URL, no scheme, hostname, ...
route_name_url: The full URL including scheme, hostname, ...
Those methods will use their parameters for the route's parameter values in order so you could say:
<%= link_to 'Pancakes!', route_name_path(att, status, date, id) %>
and :attendances would be att, :new would be status, etc. Alternatively, you could pass a Hash to the method and use the parameter names directly:
<%= link_to 'Pancakes!', route_name_url(
:attendances => att,
:new => status,
:class_date => date,
:student_id => id
) %>
I'm creating a simple quiz application where a question can have multiple answers. To improve the usability of my app, I want users to be able to edit ALL the answers for a given question in the same form:
I found this great Railscast/Asciicast episode which does almost EXACTLY what I want to do
http://asciicasts.com/episodes/198-edit-multiple-individually
However, there's a catch. My answers model is nested within questions like so:
map.resources :answers, :has_one => :question
map.resources :questions, :has_many => :answers
So when it comes time to define the route and form tag I come a bit unstuck... The tutorial suggests creating 2 new controller methods and defining the routes and form tags as follows:
map.resources :products, :collection => { :edit_individual => :post, :update_individual => :put }
<% form_tag edit_individual_products_path do %>
But this doesn't work in my case as Answers are dependent on Questions... Any ideas on how to translate this tutorial for my nested models?
Working with nested routes looks pretty from some point of view, but always become a bit tricky. In order for this to work you will have to
Fix the routes definition
Adapt the URL generators in all views (like form_for or answers_path)
Routes
First things first: Specifying associations within the routes won't allow you to add custom routes to the second class. I would do something like this:
map.resources :questions do |question|
question.resources :answers, :collection => {
:edit_individual => :post,
:update_individual => :put }
end
Views
It's really important to notice the change in URL generators:
edit_answer_path(#answer) => edit_question_answer_path(#question, #answer)
edit_individual_answer_path(#answer) => edit_individual_question_answer_path(#question, #answer)
I've made a fast adaptation of the Railscasts views:
<!-- views/answers/index.html.erb -->
<% form_tag edit_individual_question_answer_path(#question) do %>
<table>
<tr>
<th></th>
<th>Name</th>
<th>Value</th>
</tr>
<% for answer in #answers %>
<tr>
<td><%= check_box_tag "answer_id_ids[]", answer.id %></td>
<td><%=h answer.name %></td>
<td><%=h answer.value %></td>
<td><%= link_to "Edit", edit_question_answer_path(#question, answer) %></td>
<td><%= link_to "Destroy", question_answer_path(#question, answer), :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<p>
<%= select_tag :field, options_for_select([["All Fields", ""], ["Name", "name"], ["Value", "value"]]) %>
<%= submit_tag "Edit Checked" %>
</p>
<% end %>
<!-- views/answers/edit_individual.html.erb -->
<% form_tag update_individual_question_answers_path, :method => :put do %>
<% for answer in #answers %>
<% fields_for "answers[]", answer do |f| %>
<h2><%=h answer.name %></h2>
<%= render "fields", :f => f %>
<% end %>
<% end %>
<p><%= submit_tag "Submit" %></p>
<% end %>
Extra
As you may have seen, you will require the variable #question within your views, so I would recommend you to have a before_filter in your AnswersController that fetches the question object:
AnswersController
before_filer :get_question
[...]
private
def get_question
# #question will be required by all views
#question = Question.find(params[:question_id])
end
end
Enjoy your nested routes!!