I am trying to use the link_to feature to link one view to another.
The view i am calling link_to is app/views/instructors/show.html.erb and that snippet of code looks like this (namely, the second to last line of it)
<% provide(:title, #instructor.login) %>
<% courses = Course.where(:instructor_ID => #instructor.id) %>
<div class="span2">
<h1 align=center ><%= #instructor.login %></h1>
<%= link_to "Add course", new_course_path(:instructor_ID\
=> #instructor.id), :class => "btn" %>
<br>
<br>
<%= link_to "Remove course", delete_course_path(courses), :class => "btn"%>
</div>
The view I am trying to link to is is app/views/courses/show_all.html.erb and looks like this:
<% #courses.each do |course| %>
<tr>
<td><%= course.course_name %></td>
<td><%= course.instructor_ID %></td>
<td><%= link_to 'Show', course %></td>
<td><%= link_to 'Edit', edit_course_path(course) %></td>
<td><%= link_to 'Destroy', course, :method => :delete, :data => { :confirm => 'Are you sure?' } %></td>
</tr>
delete_course_path routes to app/views/courses/show_all.html.erb shown above. When I try the code above, I get the following error:
undefined method `each' for nil:NilClass
At this line:
<% #courses.each do |course| %>
Any ideas what i'm missing in my link_to?
In your show_all action, you should define a #courses instance variables. This is
<% courses = Course.where(:instructor_ID => #instructor.id) %>
not passed to show_all.html.erb.
An instance variables is a variable passed from action of controller to the view corresponding.
I suppose when you show page of instructor, your route will like this: /instructors/:id, so maybe in your show_all action of instructor controller, you need something like:
def show_all
#courses = Course.where(instructor_ID: params[:id])
render 'courses/show_all'
end
This means that #courses is nil. Did you set it in your show_all action of your controller? E.g.
def show_all
#courses = Course.all
end
Also, in your show view, you set courses to a collection of Course objects, but your "Remove course" link looks like you only want to delete one course. Why do you use the delete_course route to link to your show_all view?
Related
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]) %>
Ok so far i created an new controller with:
rails g controller home settings
In the settings.html.erb i want to display an partial so that i simply added one line:
<%= render "categories/index", :locals => {:categories => #categories} %>
So my categories/_index.html.erb looks like this, and worked:
<% for category in #categories do %>
<tr>
<td><%= category.typ %></td>
<td><%= link_to "Löschen", category,:class => 'btn btn-mini btn-danger', method: :delete, data: { confirm: 'Sind sie sicher?' } %></td>
</tr>
<% end %>
<tr>
<%= form_for Category.new do |f| %>
<td> <%= f.text_field :typ, :class => "input-small" %></td>
<td><%= f.submit "Speichern", :class => 'btn btn-mini btn-success' %></td>
</tr>
<% end %>
</table>
</div>
But now when i open localhost:3000/home/settings i get the error:
NoMethodError in Home#settings
Showing C:/Sites/rublesql/app/views/categories/_index.html.erb where line #10 raised:
undefined method `each' for nil:NilClass
Extracted source (around line #10):
7: <th></th>
8: </tr>
9:
10: <% for category in #categories do %>
11: <tr>
12: <td><%= category.typ %></td>
So my question is what did i wrong?
Categories controller:
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def destroy
#category = Category.find(params[:id])
#category.destroy
redirect_to categories_path
end
def create
#category = Category.new(params[:category])
#category.save
redirect_to categories_path
end
end
It means the #categories instance variable hasn't been set.
Check in your controller that it sets #categories = xx.
Three things I notice:
You're mixing notations with the partial. Previously you would do, render partial: "x", locals: {}, now you can drop the partial key and just send the view path in, but if you choose to do this you also remove the locals: key:
<%= render "categories/index", {categories: #categories} %>
Also:
{:categories => #categories} will make categories your local, not #categories.
However, your instanced #categories should pass through as well, so it isn't your issue.
Finally:
#categories isn't set (or if it is, it becomes nil). Either make sure your controller correctly assigns it, or otherwise check .nil? or for .present? before attempting to loop through them.
I'm creating a simple inventory app, there is a view that lists 'items'. It has tables with these rows:
<tr>
<td><%= item.title %></td>
<td><%= item.desc %></td>
<td><%= item.value %></td>
<td><%= item.room.name %></td>
<td><%= item.user.username %></td>
<td>
<%= link_to 'View', item %>
<%= link_to 'Edit', edit_item_path(item) %>
<%= link_to 'Delete', item, method: :delete, data: { confirm: 'Are you sure?' } %>
<%= link_to 'Add Comment', !?????! %>
</td>
/tr>
I have a linked model for 'comments' set up but don't know how to pass the 'item_id' to it when creating a new one.
The URL helpers actually accept the object to make a route for an association. Meaning, assuming you have a nested route for comments within items,
resources :items do
resources :comments
end
you can link_to the new_item_comments_path(item).
The method new_item_comments_path(item) makes a string URL based on the new_item_comments route, which you feed to link_to to make an HTML <a> tag.
To be clearer, in your view you would have:
<%= link_to 'View', item %>
<%= link_to 'Edit', edit_item_path(item) %>
<%= link_to 'Delete', item, method: :delete, data: { confirm: 'Are you sure?' } %>
<%= link_to 'Add Comment', new_item_comments_path(item) #-> (instead of ???) %>
In this case, the item you are passing is the reference to your current item, which allows the URL helper to make a URL for it from the route.
The Rails guide for routing should be a useful read for you.
Now that's assuming your Comment controller assigns the right stuff at the right place. You seemed to have figured that out, but I'll explain for the sake of clarity (and future visitors)
class CommentsController < ApplicationController
# GET /item/:item_id/comments/new
def new
#comment = Comment.new
#item = Item.find(params[:item_id])
#comment.item = #item
# render
end
# POST /item/:item_id/comments
def create
#comment = Comment.new(params[:comment])
#item = Item.find(params[:item_id])
#comment.item = #item
# if #comment.save blah
end
end
All credit should go to #jonallard
The solution is all about routing it seems, you need to pass a url to the form that makes new comments (linked models).
to do this:
Add this (or similar depending on object names) to the page that is calling the creation:
<%= link_to 'Add Comment', new_item_comment_path(#item) %>
In both the new and the create method of the comments_controller there is a line starting #comment = Comment.new. Under that line add:
#item = Item.find(params[:item_id]) AND
#comment.item = #item
edit the top line of the comments template for to: <%= form_for(#comment, {:url => item_comments_path(#item)}) do |f| %>
Edit routes to somethings like:
resources :items do
...
resources :comments
end
and Read this: http://guides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects!
As mentioned before all credit goes to #jonallard, his answer and his expertise.
I'm new to Ruby on Rails & to web programming.
In my application I have two models; Directorate which has_many :users, and User which belongs_to :directorate.
When creating a new user, I use <%= f.collection_select(:directorate_id,Directorate.all, :id, :name) %> in the new.html.erb form to assign the new user to specific directorate. However, I want to build a user-friendly interface for the dba that lists all directorates; and listing all users beside each directorate, with a link to assign any user to a specific directorate.
What I did is the following:
In Directorate model, I defined the following function:
def assign_user!(user)
user.update_attributes(directorate_id: #directorate)
end
and in the directorates controller, I defined the following action:
def assign_user
#directorate = params[:directorate]
assign_user! params[:user]
redirect_to directorates_url
end
Now, directorates/index.html.erb contains the following:
<h1>Listing directorates</h1>
<table>
<tr>
<th>Name</th>
<th>Info</th>
</tr>
<% #directorates.each do |directorate| %>
<tr>
<td><%= directorate.name %></td>
<td><%= directorate.info %></td>
<td><%= link_to 'Show', directorate %></td>
<td><%= link_to 'Edit', edit_directorate_path(directorate) %></td>
<td><%= link_to 'Destroy', directorate, confirm: 'Are you sure?', method: :delete %></td>
<%= #directorate = directorate%>
<%= render 'users_form' %>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Directorate', new_directorate_path %>
and, -users_form.html.erb contains the following form (which is supposed to list all users beside each directorate, with a link to assign any user to a certain directorate):
<h1>Listing Users</h1>
<table>
<tr>
<th>User Name</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.username %></td>
<td><%= link_to 'Assign to Current Directorate', {controller: 'directorates', action: 'assign_user', directorate: #directorate, user: user}, :method => :put %></td>
</tr>
<% end %>
</table>
<br />
Here is the problem, when listing directorates & click on the 'Assign to Current Directorate' I receive the following error:
http://127.0.0.1:3000/directorates/assign_user?directorate=4&user=5
ActiveRecord::RecordNotFound in DirectoratesController#update
Couldn't find Directorate with id=assign_user
Rails.root: /home/ehab/sites/IAMS
Application Trace | Framework Trace | Full Trace
app/controllers/directorates_controller.rb:61:in `update'
Request
Parameters:
{"_method"=>"put",
"authenticity_token"=>"L5tz3hv2IW0meE79qUq0/tjfGKwDlpC23hOeAWtmTvk=",
"directorate"=>"4",
"user"=>"5",
"id"=>"assign_user"}
It's clear that the params is submitting "id"=>"assign_user" which I don't want, what i want is "id"=>"directorate.id" (4 in the above example). What shall I do to fix this issue?!
first of all your routes should say that assign_user is a member method on a certain directorate object:
resources :directorates do
member do
put :assign_user
end
end
second you say you define assign_user! in Directorate model and assign_user in DirectoratesController but both methods imply that they share same object state like instance variable #directorate which is not true
your controller method assign_user should look vaguely like
def assign_user
#directorate = Directorate.find params[:id]
#user = User.find params[:user_id]
#directorate.assign_user! #user
end
and model method should look like
def assign_user!(user)
user.update_attributes(directorate_id: self.id)
end
and even that i would switch around to instead of telling Directorate to change user's attributes you would tell User to assign itself to whatever controller wants.
and the final bit is your link that assigns user to directorate:
link_to 'Assign to Current Directorate',
assign_user_directorates_path(#directorate, :user_id => user)
0 lines of code above were tested for even syntactical correctness, DO NOT copy-paste, read and understand
Here's my index action in the books controller: http://pastebin.com/XdtGRQKV
Here's the view for the action i just mentioned: http://pastebin.com/nQFy400m
Here's the result without being logged in: http://i.imgur.com/rQoiw.jpg
Here's the result when i'm logged in with the user 'admin': http://i.imgur.com/E1CUr.jpg
So the problem is that, in the view, before line 25 the 'user' variable seems to be empty ( or not loaded), and after line 25 the variable 'user' has the expected values.
I have tried initializing a variable in the index method of the books controller but get exactly the same results.
Thanks in advance!
BTW had to make the links text because of stackoverflow limit.
This:
user = User.find_by_id(session[:user_id])
should be in controller, not in view (MVC!) like this:
#user = User.find_by_id(session[:user_id])
Then in your view, as #Voyta answered, use <%= #user.username %>. Code inside <% %> is evaluated, but not rendered, so if you want to put result in your html, you need to add =.
And all yours if user and if user.admin == 1 would look much better this way:
<% if user %>
<td><%= link_to 'Show', book %></td>
<% if user.admin == 1 %>
<td><%= link_to 'Edit', edit_book_path(book) %></td>
<td><%= link_to 'Delete', book, :confirm => 'Are you sure?', :method => :delete %></td>
<% end
end
%>
If you use if in single line like here:
<%
if user
if user.admin == 1
%>
<%= link_to 'New book', new_book_path %>
<%
end
end
%>
You can write the same like this:
<%= link_to 'New book', new_book_path if user && user.admin == 1 %>
You didn't output user.username. It should be <%= user.username %>, not <% user.username %>