Rails link_to not working correctly - ruby-on-rails

I am trying to put in a link_to on my table to go to the show action but it is putting the URL as /admin/vulnerabilities.object_id instead of /admin/vulnerabilities/object_id
my index view is:
...
<% #vulnerabilities.each do |vulnerability| %>
<tr>
<td><%=link_to vulnerability.id, admin_vulnerabilities_path(vulnerability) %></td>
<td><%= vulnerability.type %></td>
<td><%=h truncate(vulnerability.description, :length => 80) %></td>
<td><%= vulnerability.published %></td>
<td><%= vulnerability.modified %></td>
<td><%= link_to vulnerability.href, vulnerability.href , target: :_blank %></td>
</tr>
<% end %>
...
I have a show.html.erb template setup and my show action is as follows:
def show
#vulnerabilities = Vulnerability.find(params[:id])
end
From what I can see, this should work but when clicking the links it just redirects to the index page, effectively refreshing it and not using my show page at all.

It would be helpful if you added the relevant parts of your routes.rb file to your question, but I speculate that the problem is that admin_vulnerabilities_path(vulnerability) should be admin_vulnerability_path(vulnerability).
Also, as noted in the comments, it is probably better to use #vulnerability as your instance name since find will return a single record.

Related

Rails Access Association attributes issue

I have an html table that renders a partial as follows
<tbody id="horse_logs">
<%= render #horse_logs %>
</tbody>
This calls _horse_log.html.erb and iterates through each element in #horse_logs
<tr id="<%= dom_id(horse_log) %>">
<td><%= horse_log.id %></td>
<td><%= horse_log.name %></td>
<td><%= horse_log.boarder.first_name%></td> <!-- This is the association I want to access -->
<td><%= horse_log.arrival_date %></td>
<td><%= horse_log.monthly_boarding_fee %></td>
<td><%= link_to '<i class="link blue large id card icon"></i>'.html_safe, horse_log_path(horse_log)%></td>
<td><%= link_to '<i class="link green large edit icon"></i>'.html_safe, edit_horse_log_path(horse_log), remote: true %></td>
<td><%= link_to '<i class="link red large remove icon"></i>'.html_safe, horse_log_path(horse_log), method: :delete, :data => {:confirm => 'Are you sure?'}, remote: true %></td>
</tr>
The issue is that accessing the boarder association inside the partial gives the following error
undefined method `first_name' for nil:NilClass
So basically the way rails implements this, they seem to be stripping the association data. The association is set up in my models correctly, and I can access the data in all other ways EXCEPT inside the partial.
How can I force rails to include the entire association.
here is my controller method if this helps
def index
#horse_logs = HorseLog.all.paginate(:page => params[:page], :per_page => 9).order("created_at DESC")
#horse_log = HorseLog.new
end
There may be a better way to do this but I would try.
<tbody id="horse_logs">
<% #horse_log.each do |horse_log| %>
<%= render 'horse_logs', horse_log: horse_log %>
<% end %>
</tbody>
If you get the same error, then you will need to make sure that your association is set up correctly.
Does every horse_log have a boarder? If not, you will get this error every time you run this code. you will need to check that hourse_log.boarder isn't nil.
For a quick fix, try this. It will prevent the error and return nil gracefully
<td><%= horse_log.try(&:boarder).try(&:first_name) %></td>

How to update instance with params of another instance from a view

I want to write a method that changes a WorkShift to booked:true and booked_by:current_member.member_id. However I get the error
"undefined method `book' for #< WorkShift:0xc973ce0>"
and I don't understand why. I just want it to be a button and not a separate edit view.
Edit: Turns out I put the book method in the wrong place, but the same method in work_shifts.rb throws a "undefined method `to_model' for true:TrueClass" instead. I'm (obviously) unsure what is the correct way to call a custom method that updates one object with the params of another from a view.
My index view:
<% #work_shifts.each do |work_shift| %>
<tr>
<td><%= work_shift.date %></td>
<td><%= work_shift.booked_by %></td>
<td><%= work_shift.booked %></td>
<td><%= work_shift.start_time.strftime("%H:%M") %></td>
<td><%= work_shift.stop_time.strftime("%H:%M") %></td>
<td><%= button_to 'Book', work_shift.book(current_member) %></td>
<% if current_member.admin? %>
<td><%= link_to 'Edit', edit_work_shift_path(work_shift) %></td>
<td><%= button_to "Ta bort", work_shift, :method=>:delete, :work_shift=>:destroy %></td>
<% end %>
</tr>
<% end %>
WorkShift.rb:
def book(member_id)
self.update(booked:true, booked_by: member_id)
end
routes.rb
resources :work_shifts do
member do
get 'book'
end
end
I'm new to rails and learning on the go, and I'm guessing the solution is trivial, but I just can't find any questions or documentation that helps with what I want to do.
Since you're trying to modify a resource's single field, the book link should be a PATCH request and not GET.
Change your routes to
resources :work_shifts do
member do
patch 'book/:member_id' => 'work_shifts#book', as: 'book'
end
end
This will generate the following route
book_work_shift PATCH /work_shifts/:id/book/:member_id(.:format) workshifts#book
And update your book action as
def book
#work_shift = WorkShift.find(params[:id])
#work_shift.book(params[:member_id])
# redirect to some view
end
And modify your model method accordingly.
def book(member_id)
self.update(booked:true, booked_by: member_id)
end
And replace the your view from
<%= button_to 'Book', work_shift.book(current_member) %>
to a link (You can style it as a button if you want)
<%= link_to 'Book', book_work_shift_path(work_shift, current_member.member_id), method: :patch %>
Thats it!

Rails 4 How to make a page display a user's list of dogs

I have been practicing working on this rails application where I want to allow registered users to put up profiles of their dogs. But I just can't get the My Dogs page to display dogs that belong only to the current logged in user.
I already have the dog and user models linked via Active Record (User has_many :dogs, Dog belongs_to :user) but I don't know what to type in my dogmenu view to display only dogs that belong to the current logged in user. This is what I have so far:
views\access\dogmenu.html.erb <-- Notice that the page that will display the dogs for the current logged in user is located in the view of another controller.
<div id="dogdisplay">
<table>
<tr>
<th>Dog Name</th>
<th>Breed</th>
</tr>
<% Dog.all.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
</table>
</div>
Thank you.
You will need two things to make this work:
A User object for the logged in user
Filter the dog list based on that id
1. Current User
This is pretty straightforward, you should be able to find this with a little googling. The big question is whether you've implemented your own user management, or you're using something like Devise to manage that.
If it's Devise, take a look at Rails Devise: get object of the currently logged in user?
If you wrote your own, you could take a look at how Devise or other user management gems provide access to the current user object. I'll leave that up to you because it seems beyond the scope of your question
2. Filter the dog list
This is pretty simple, you've got a few options:
From the view
current_user.dogs.each do |d|
Dog.where(user: current_user).each do |d|
Dog.where(user_id: current_user.id).each do |d|
From the controller
What #Sean Huber suggested is cleaner - use any of my methods above, but from the controller. E.g.
#dogs = current_user.dogs
In short, only take the dogs that have the user id matching the current user's.
I would suggest you set an instance variable in your controller action for the current user's dogs. Something like this:
def dogmenu
# this assumes you have a current_user already defined
#dogs = current_user.dogs
end
Then switch your view to use the instance variable #dogs:
<div id="dogdisplay">
<table>
<tr>
<th>Dog Name</th>
<th>Breed</th>
</tr>
<% #dogs.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
</table>
</div>
You need to retrieve the dogs related to the current user. Since these are the user's dogs, the logic should reside in the UsersController:
In _controller/users_controller.rb_
def your_method_name
#user = User.find(current_user.id)
#dogs = #user.dogs
render :dogmenu
end
Then in views/users/dogmenu.html.erb
<div id="dogdisplay">
<table>
<tr>
<th>Dog Name</th>
<th>Breed</th>
</tr>
<% #dogs.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
</table>
</div>
These are user dogs so the view really belongs in the users folder.
To get current user dogs, you can use object current_user
Change this
Controller
def dogmenu
#dogs = current_user.dogs
end
View
<% #dogs.each do |d| %>
To make current_user can execute in view put a helper method.
class ApplicationController < ActionController::Base
helper_method :current_user
def current_user
#current_user ||= User.find_by_id(session[:user])
end
end
Finally you can use current_user in your view or helper
<% current_user.dogs.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
It's good for trying the first one where you're using instance variable. Hopefully it can help.

Display Ancestry name instead of id

My applications currently uses the Ancestry gem to create a navigation tree.
How do I display the name of a page which is the parent of another in the index view?
i.e. currently I do...
<% #pages.each do |page| %>
<tr>
<td><%= link_to page.name, edit_page_path(page) %></td>
<td><%= page.ancestry %></td>
</tr>
<% end %>
I want the page.ancestry to be the parent's name, not the ID.
<td><%= page.parent.name %></td>
isn't it working?

Returning data from database to another page in rails

How can I return data from the database on another page?
I can file this under: views / posts / index.htm.erb
<h1>Listing posts</h1>
<table>
<tr>
<th>Titulo</th>
<th>Conteudo</th>
<th>Categoria</th>
<th>Criado em</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #posts.each do |post| %>
<tr>
<td><%= post.titulo %></td>
<td><%= post.conteudo %></td>
<td><%= post.category.name %></td>
<td><%= post.created_at.strftime("%d/%m/%Y") %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Delete', post, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Post', new_post_path %>
And I wanted to display these values ​​on another page: views / home / blog.html.erb
How do I do this? Could you explain all the steps so that I can display these values ​​in my other page.
Thanks Kocur4d
but how do I get only some information? eg: I would like that to appear in the title of the post page like this way (in blog.html.erb):
<div class="post-title">
<h2 class="title"> <a href="link_to_post"> **<% = post.titulo%>** </ a> </ h2>
</ div>
Step 1. Create controller
In your app root directory run:
rails g controller home blog
Modify controllers/homes_controller.rb :
class HomesController < ApplicationController
def blog
#posts = Post.all
end
end
Your controllers/posts_controller.rb should be already set up. Minimum what you need for your question is to have index method defined you might have other methods as well:
class PostsController < ApplicationController
def index
#posts = Post.all
end
end
Step 2. Extract Partial
change views/posts/index.htm.erb :
<h1>Listing posts</h1>
<%= render partial: 'shared/posts', object: #posts %>
<%= link_to 'New Post', new_post_path %>
create/modify views/home/blog.html.erb :
<h1>Listing posts</h1>
<%= render partial: 'shared/posts', object: #posts %>
<%= link_to 'New Post', new_post_path %>
create views/shared/_posts.html.erb :
<table>
<tr>
<th>Titulo</th>
<th>Conteudo</th>
<th>Categoria</th>
<th>Criado em</th>
<th></th>
<th></th>
<th></th>
</tr>
<% posts.each do |post| %>
<tr>
<td><%= post.titulo %></td>
<td><%= post.conteudo %></td>
<td><%= post.category.name %></td>
<td><%= post.created_at.strftime("%d/%m/%Y") %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Delete', post, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
Step 3. Set up routes.
You should have something like this in your routes.rb file:
resources :posts or match 'posts/index' => 'posts#index'
add this to config/routes.rb:
match 'home/blog' => 'home#blog'
so it might look like this(there is few variants):
config/routes.rb:
YourAppName::Application.routes.draw do
root to: 'posts#index'
resources :posts
match 'home/blog' => 'home#blog'
end
Now when you start rails server(assuming standard configuration) and visit:
127.0.0.1:3000/posts/index and 127.0.0.1:3000/home/blog
you should see same content.
This should work copy-and-paste but I could make some typos and other small mistakes(hope not, if ill find any ill try to edit them asap). In general look at it as you need 3 steps to forward http request down your rails application stack.
Map url to controllers using routes.
Create controllers and inside prepare data for views.
Display data in Views.
Look around in Rails Guides, Rails for Zombies and Rails Tutorial for more info.
---------Upadate to your second question-----------
I don't really understand what would you like to achieve?? At the moment both index.html.erb and blog.html.erb showing the same data, that was what you ware asking for?
post representing one post and is available in sharde/_posts.html.erb. You can't reference it from index.html.erb or blog.html.erb.
#posts represents all the posts and its available in index.html.erb or blog.html.erb.
render partial: 'shared/posts', object: #posts -- this line say "Hey man! Paste here content of shared/posts file, and btw I have here a local variable #posts so if you need to use that date in shared/posts file Ill name it posts from in side there"
To make them look different modify both files and part that will be identical for both of them is in a sharde/_posts.html.erb.
Try for example remove this line:
<td><%= post.category.name %></td>
from shared file to see what is going to happen.
Add some html tags and thinker with it.
Rails has may helper methods available' to find out about them check the links I give you and google, google, google.
Try to add some links with link_to helper
In your home controller, for the blog method, set #posts as you need...
Maybe
#posts = Post.all

Resources