Rails Routing Questions - ruby-on-rails

I am very new to Ruby on Rails and I have been working with a project while learning but I have run into an issue. I am trying to set up a link from a view under a "task" controller to a view for new timetracks. I am attempting to link on the view like so:
<%= link_to "New Timetrack", new_project_list_task_timetrack_path(#project, #list, #task) %>
And I am getting this error:
No route matches {:action=>"new", :controller=>"timetracks", :project_id=>nil, :list_id=># < List id: 1, name: "Test", description: "Test", created_at: "2013-12-18 21:00:39", updated_at: "2013-12-18 21:00:50", project_id: 1, default: nil>, :task_id=>#>Task id: 1, description: "First Task", completed: false, list_id: 1, created_at: "2013-12-18 21:00:57", updated_at: "2013-12-18 21:00:57", default: nil>}
I made sure that there was an action "new" in the timetracks controller. I am creating the link the way above because of how I saw Rails scaffold the relation between projects and lists which was like so:
<%= link_to "Create To-Do", new_project_list_path(#project) %>
So I'm stumped and would like some help. Any information is appreciated!

Try to use new_project_timetrack_path
If it helpless, look at the output of bash command rake routes and find route that you need.

in your config/routes.rb must be rows like these:
resources :projects do
resources :lists do
resources :tasks do
resources :timetracks
end
end
end
and then rake compile path like
host:3000/projects/<project_id>/lists/<list_id>/tasks/<task_id>/timetracks/new
I hope this can help you.

Related

Why does rails console give different size of relationship than in the server?

My relationship between posts and comments are showing differently in the rails console and the web server! How could that be? I was confused because a partial was rendering with wrong links, and I thought something else was wrong, but the partial should not have rendered at all because the collection should be empty! I even use an if/else to check the size, and it was still showing the partial for the empty relationship!
Rails Console:
irb(main):033:0> p=Post.find(6)
=> #<Post id: 6, title: "Yahoo", comment: "The home page.", link: nil, user_id: nil, created_at: "2013-10-06 21:53:24", updated_at: "2013-10-07 00:43:25">
irb(main):034:0> p.comments.size
=> 0
posts/show.haml:
%h2 Comments
Post ID:
=#post.id
, Comment Size:
=#post.comments.size
- if #post.comments.empty?
No comments.
- else
= render #post.comments
Browser: http://127.0.0.1:3000/posts/6
Comments
Post ID: 6 , Comment Size: 1
Commenter:
comments/_comment.haml: Doesn't seem relevant...
Rails 4.0.0, ruby 2.0.0p247 (2013-06-27) [i386-mingw32]
Maybe there is a form for new comment somewhere on this page and you build new comment in controller:
#new_comment = #post.comments.build
That's why #post.comments.count is 1. You could rewrite your code:
= #post.comments.reject{ |t| t.new_record? }.count
UPD.
There is a nicer way to do this thing: instead of adding reject method you could add scope in your Comment model:
scope :saved, where('id is not ?', nil)
And then in view:
#post.comments.saved.count

Creating new child in nested routes

This one is driving me crazy. I've got a nested relationship between two models in my project, and I decided I did not want it to be shallow, since the child object (years) has no meaning outside the context of the parent (festivals).
So I sort of de-shallowed the relationship wherever I could find a reference to it, but I find myself unable to access the page to create a new child object.
Here's the url as I understand it should be: /festivals/1/years/new
from routes.rb:
resources :festivals do
resources :years
end
From years_controller.rb:
# GET festivals/1/years/new
# GET festivals/1/years/new.json
def new
#festival = Festival.find(params[:festival_id])
#year = #festival.years.build
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #year }
end
end
And the button users press to get to the New page (on the Show page for the parent object):
<%= link_to 'Add Year', new_festival_year_path(#festival), :class => 'btn' %>
That takes the user to the correct URL, but I get:
No route matches {:action=>"show", :controller=>"years", :festival_id=>#<Festival id: 7, name: "Improganza", founded: nil, logo: "", mission: "This is that one that people spend a lot of money t...", city: "Honolulu", state_code: "HI", country_code: "US", created_at: "2013-07-26 14:49:19", updated_at: "2013-07-26 14:49:19">}
I created a new Rails project and set up scaffolds using Akria Matsuda's nested_scaffold gem, just to compare that output with my code... the resulting files look as I've shown here. I have no idea what I might be missing.
Just for good measure, the output of my rake routes:
festival_years GET /festivals/:festival_id/years(.:format) years#index
POST /festivals/:festival_id/years(.:format) years#create
new_festival_year GET /festivals/:festival_id/years/new(.:format) years#new
edit_festival_year GET /festivals/:festival_id/years/:id/edit(.:format) years#edit
festival_year GET /festivals/:festival_id/years/:id(.:format) years#show
PUT /festivals/:festival_id/years/:id(.:format) years#update
DELETE /festivals/:festival_id/years/:id(.:format) years#destroy
festivals GET /festivals(.:format) festivals#index
POST /festivals(.:format) festivals#create
new_festival GET /festivals/new(.:format) festivals#new
edit_festival GET /festivals/:id/edit(.:format) festivals#edit
festival GET /festivals/:id(.:format) festivals#show
PUT /festivals/:id(.:format) festivals#update
DELETE /festivals/:id(.:format) festivals#destroy
GET /festivals(.:format) festivals#index
POST /festivals(.:format) festivals#create
GET /festivals/new(.:format) festivals#new
GET /festivals/:id/edit(.:format) festivals#edit
GET /festivals/:id(.:format) festivals#show
PUT /festivals/:id(.:format) festivals#update
DELETE /festivals/:id(.:format) festivals#destroy
Try this:
<%= link_to 'Add Year', new_festival_year_path(#festival.id, :class => 'btn' %>
or
<%= link_to 'Add Year', new_festival_year_path({festival_id: #festival.id}, :class => 'btn' %>
according to the error you're getting
:festival_id=>#<Festival id: 7, name: "Improganza", founded: nil, logo: "", mission: "This is that one that people spend a lot of money t...", city: "Honolulu", state_code: "HI", country_code: "US", created_at: "2013-07-26 14:49:19", updated_at: "2013-07-26 14:49:19">}
the router is getting your whole festival param as the input for :festival_id
I think you are merging together the #new and #year actions in the years_controller and that might be causing some problems.
# GET festivals/1/years/new
# GET festivals/1/years/new.json
def new
#festival = Festival.find(params[:festival_id])
#year = #festival.years.build
end
def create
#festival = Festival.find(params[:festival_id])
#year = #festival.years.create(...)
#...fill in the rest of the method...
end
You also should update your link:
<%= link_to 'Add Year', new_festival_year_path(festival_id: #festival), :class => 'btn' %>
I created a short quiz on nested resources that might be helpful.
The answer was fairly silly. In my Rails server log (which I need to train myself to pay more attention to), I saw the some lines indicating a problem in line 63 of my _form.html.erb partial.
That line was:
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
festival_year_path(#festival), :class => 'btn' %>
Oops. Why I ever decided the "Cancel" button should take you to a year (that, of course, would not exist) is beyond me. I changed it to festival_path(#festival) and it's all good.
Thanks, everyone, for your help. I'm a newcomer to StackOverflow and to Rails in general. It really makes me feel welcome that I got such quick responses!

Rails 3.1 - link_to generates a "no route matches" error on <ActiveRecord::Relation>.first

In a view I can do this and the link works fine:
<%= link_to "Most popular comment", comment_path( Comment.find(5) ) %>
So I know that my routes are set up to show an individual comment record via comment_path(). However when I try this:
<%= link_to "Most popular comment", comment_path( #post.comments.order("vote_cnt DESC").first )
I get a "No route matches {:action=>"show", :controller=>"comments"}" error. But I know this not an accurate error description because the first link_to() statement listed above works. I've confirmed the route exists - from rake routes I get this:
comment GET /comments/:id(.:format) {:action=>"show", :controller=>"comments"}
In IRB I can see that the two statements I'm passing to comment_path() both generate the same class, namely "Comment":
irb(main):022:0> top_comment = post.comments.order("vote_cnt DESC").first
Comment Load (0.6ms) SELECT "comments".* FROM "comments" WHERE "post_id" = 2 ORDER BY vote_cnt DESC LIMIT 1
=> #<Comment id: 5, heading: nil, body: nil, user_id: 5, created_at: "2012-02-03 01:23:30", updated_at: "2012-02-03 01:23:30",vote_cnt: 0>
irb(main):023:0> top_comment.class
=> Comment(id: integer, heading: string, body: text, user_id: integer, created_at: datetime, updated_at: datetime, vote_cnt: integer)
irb(main):024:0> comment_5 = Comment.find(5)
Comment Load (3.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."id" = $1 LIMIT 1 [["id", 5]]
=> #<Comment id: 5, heading: nil, body: nil, user_id: 5, created_at: "2012-02-03 01:23:30", updated_at: "2012-02-03 01:23:30", vote_cnt: 0>
irb(main):025:0> comment_5.class
=> Comment(id: integer, heading: string, body: text, user_id: integer, created_at: datetime, updated_at: datetime, vote_cnt: integer)
If both statements generate the same class of object, how can link_to() work with one and cause a route error on the other, especially when both resolve to the same exact record? I tried:
<% top_comment = post.comments.order("vote_cnt DESC").first %>
<%= link_to "Most popular comment", comment_path( top_comment )
and that generates the same "No path matches..." error.
Any ideas what is going on here? It seems that link_to() works well with a record that comes from a straight up query against a table, but errors out on that same record if was retrieved via an ActiveRecord::Relation action. Why? How can that be?
Ok, this one is weird. Have you checked what's returned by #post.comments.order("vote_cnt DESC").first in your view (either by printing it, or debugger/pry) ?
[converting my comment above into an answer]
Sorry guys - programmer logic error.
I tried "rkb"s suggestion of ...first.id, and got an error saying I can't get the ID of a nil object. This link_to call was in a loop:
#top_ten_posts each do |post|
...
end
Since they are recent posts, one of them didn't have any comments. Duh! My code should check for that first.
My bad. However, it is very frustrating that link_to won't give you a clear indication that you have passed it a nil object. "No route matches..."?!?!?! Pretty poor error message for the situation!

Route errors when using namespace routes

How do you deal with form_for's when the routes are namespaced? I am getting some weird route errors that I really expect to get.
For example, let's say you have a controller called Admin::CompaniesController in
your :admin namespace in your routes.rb:
namespace :admin do
resources :companies
end
Most things work just fine, but I get an error when I render a new form. Here's the code:
<%= simple_form_for(#company, :url => admin_company_path(#company)) do |f| %>
And here's the error message:
ActionView::Template::Error: No route matches {:action=>"show", :controller=>"admin/companies", :id=>#<Company id: nil, name: nil, phone_number: nil, address: nil, postal_code: nil, is_enabled: true, courses_created: 0, province_id: nil, theme_id: nil, payment_plan_id: nil, created_at: nil, updated_at: nil>}
How can I get rails to play nice here? I obviously want one url for edits, and another for new forms. Usually, I'd never even have to put :url in my form_for statements, but because of the nesting, I am forced to.
I have no idea what to do here now, at least not elegantly.
Try using simple_form_for([:admin, #company]) do |f|
I believe I just have to pluralize the path at the end of the path, like this:
<%= simple_form_for(#company, :url => admin_companies_path(#company)) do |f| %>
This is not what I would have expected. I just guessed at it. This is not a valid route or anything, but it seems to work for puts and posts.

Ruby/Rails Way to Check if object in an Array exists in other Array

Think of these lines of code :
#boss_locations = BossLocation.order('min_level asc').all
#discovered = current_user.discovered_locations.includes(:boss_location).all
The first one gets all available boss locations. The second one, gets all the discovered user locations(user_id, boss_location_id) and also includes the boss_location object.
Now, in my view, i want to present every boss location and a message like 'Discovered' or 'Not Discovered', based on whether a boss location exists on #discovered.
Now, my question is how can i feed my view with an easy way to do that. I could just traverse both arrays, but i'm pretty sure it's not the better way. Maybe there is a nice way to map all the boss locations based on the discovered boss locations for the user. How would you do it ?
EDIT - The variables have :
#boss_locations :
=> [#<BossLocation id: 670261930, name: "Fire Swamp", location_index: 1, min_level: 5, needed_gold_to_open: 500, created_at: "2011-05-18 05:35:48", updated_at: "2011-05-18 05:35:48">, #<BossLocation id: 723149845, name: "Rabbit Remains", location_index: 3, min_level: 15, needed_gold_to_open: 3000, created_at: "2011-05-18 05:35:48", updated_at: "2011-05-18 05:35:48">, #<BossLocation id: 81327760, name: "Grateful Plains", location_index: 2, min_level: 10, needed_gold_to_open: 1200, created_at: "2011-05-18 05:35:48", updated_at: "2011-05-18 05:35:48">]
#discovered :
=> [#<DiscoveredLocation id: 736487645, user_id: 986759322, boss_location_id: 670261930, created_at: "2011-05-22 05:37:01", updated_at: "2011-05-22 05:37:01">, #<DiscoveredLocation id: 736487646, user_id: 986759322, boss_location_id: 723149845, created_at: "2011-05-22 05:37:06", updated_at: "2011-05-22 05:37:06">, #<DiscoveredLocation id: 736487647, user_id: 986759322, boss_location_id: 81327760, created_at: "2011-05-22 06:01:35", updated_at: "2011-05-22 06:01:35">]
This is a lot of logic to put in a controller or view; consider creating a discovered? method on the BossLocation model. That way you could iterate through #boss_locations and call discovered? on each:
<% #boss_locations.each do |bl| %>
<div>
<%= "#{bl.name}: #{bl.discovered?(current_user)}" %>
</div>
<% end %>
The method would probably look like this:
class BossLocation < ActiveRecord::Base
def discovered?(user)
user.discovered_locations.map(&:boss_location).include?(self)
end
end
I commented above and you seemed to like the idea, so I wrote it out.
To encapsulate your data-model better, you'll want to modify your model class.
class BossLocation < ActiveRecord::Base
has_many :discovered_locations
has_many :users, :through => :discovered_locations
def discovered_by?(user)
self.users.include?(user)
end
end
Then all you need in your controller is:
#boss_locations = BossLocation.order('min_level asc').all
And in your view:
<% #boss_locations.each do |boss_location| %>
<div>
<%= boss_location.name %>:
<%= boss_location.discovered_by?(current_user) ? 'Discovered' : 'Not Discovered' %>
</div>
<% end %>
As the objects in the two arrays are not identical, you might need to iterate in a custom way:
<% #boss_locations.each do |boss_location|
<div>
<%= boss_location.name %>:
<%= #discovered_boss_locations.inject('Not Discovered') { |result, element| result = 'Discovered' if element.boss_location_id == boss_location.id}
</div>
<% end %>

Resources