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
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
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!
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!
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.
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 %>