I have created model, view and controller:
$ rails generate scaffold Post name:string title:string content:text
I run server and I see list of posts if I open in the browser http:\localhost:3000\posts.
Now I need to create link to this page. Something like:
<%= link_to("settings", { :controller => 'groups', :action => 'index'}) %>
But I get error on opening this page:
Couldn't find Group with ID=index
How ca I create link to http:\localhost:3000\posts and which action do I use in this case?
I think the path helpers are excellent in these cases. You could do it like this:
<%= link_to("Posts", posts_path) %>
posts_path in this case will link to http://localhost:3000/posts
When you use use resources :posts in your routes.rb you automatically get a few path helpers. For example:
posts_path # /posts
post_path(#post) # /posts/1
edit_post_path(#post) # /posts/1/edit
new_post_path # /posts/new
If you have a route such as:
resources :groups
In config/routes.rb then you will have the helper groups_path. You can use rake routes to see all of your routes and helpers, but in this case you will have:
groups_path
group_path(#group)
edit_group_path(#group)
Polymorphic Routes Documentation
Related
When handling validation errors in a User form on my rails project, I have the instruction render 'new' if the user is not valid.
However, when this occurs, the url in the search bar changes.
Originally, it's https://localhost:3000/signup but when the user submit the forms and the render 'new' occurs, the URL becomes https://localhost:3000/users
Why is that?
Here's my routes.rb
Rails.application.routes.draw do
# Resources
resources :users, only: [ :new, :create ]
# Application root
root 'static_pages#home'
# Static pages
get '/help', to: 'static_pages#help'
get '/contact', to: 'static_pages#contact'
# Users
get '/signup', to: 'users#new'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Thanks,
In the Rails REST conventions you use different URI's to display the form to create a resource and for the forms action attribute which you POST to.
Lets say you have:
resources :pets
This gives us:
GET /pets/new => pets#new
POST /pets => pets#create
We then have a typical form:
# posts to /pets
<%= form_for(#pet) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
And a run of the mill controller:
class PetsController < ApplicationController
def new
#pet = Pet.new
end
def create
#pet = Pet.new(pet_params)
if #pet.save
redirect_to #pet
else
render :new
end
end
# ...
end
So when the user visits /pets/new and fills in the form the browser url should read /pets if the form is invalid. This is the intended behavior - posting to a different URL avoids a myriad of cache and history related issues.
From a restful standpoint its also correct - you're no longer viewing the new action - you're viewing the results of attempting to create a resource. The former is idempotent - the latter is not.
You need to recognize that the line render :new is short for render template: 'pets/new'. It does not redirect and it does not call the new action in the controller. It simply renders the template and returns it as the response to the current request.
The reason this is happening is because of the way Rails handles routes. Most likely, the form on your signup page has something like:
<?= form_for #user do |f| ?>
If you look at the generated HTML you'll notice that the form is POSTing to the url '/users'. So when the signup form is submitted, the app is going to redirect you to /users.
This is the normal behavior in Rails. (see Rails Guides)
If you want the URL to look like /signup you can add a named route for it:
# Users
get '/signup', to: 'lead_magnets#new'
post '/signup', to: 'lead_magnets#create'
Then in your signup form you'll need to explicitly reference the new signup path:
<?= form_for #user, url: signup_path do |f| ?>
The generated HTML should look like
<form class="new_user" id="new_user" action="/signup" method="post">
You need to add
post '/signup', to: 'users#new'
Did you try to include recognize path?
Rails.application.routes.recognize_path
The reason for this is because when you submit your form, you're submitting it to some action from your new view. The action that the form submits to has a path, and you can see what the path is by typing:
rake routes
in your console and searching for the create action. When your validation fails in the create action, you call render 'new'.
When you render a template, the url of the page being rendered will be the url / path of the controller action that rendered the template.
In your case, whatever action you have that calls render 'new' will be the one determing the url once your template is rendered.
I'm implementing a voting system to my blog's comments, using the acts_as_votable gem.
However, I'm getting a routing error: no route matches. missing required keys: [:id]
#routes.rb
resources :articles do
resources :comments do
member do
put "like", to: "comments#upvote"
end
end
end
# comments controller
def upvote
#comment.upvote
redirect_to :back
end
# comments/show.html.haml
= link_to like_article_comment_path(#comment), method: :put do
= #comment.get_upvotes.size
If you use rake routes | grep like (to fatch that route), you'll get:
like_article_comment PUT /articles/:article_id/comments/:id/like(.:format) comments#upvote
So you're missing the first parametar - :article_id in your link. Should be:
= link_to like_article_comment_path(#article, #comment), method: :put do
= #comment.get_upvotes.size
Also add the #article logic in your upvote method.
I have been using Rails 3 and am trying to use Rails 4. I am following a ToDo tutorial here: http://www.codelearn.org/ruby-on-rails-tutorial/introduction-views-layouts-helpers-assets-pipeline
I am trying to delete the ToDo item using the Rails 'link_to' helper method, and have been looking up online and have not been able to get it to work for the past 90 minutes so I decided to ask for help.
Here is the error message I am getting:
Routing Error
No route matches [DELETE] "/todos/delete_path"
Here is my 'rake routes' from the terminal:
Prefix Verb URI Pattern Controller#Action
todos_index GET /todos/index(.:format) todos#index
todos_delete DELETE /todos/delete(.:format) todos#delete
Here is the 'link_to' helper method from inside of the:
index.html.erb
<%= link_to 'Delete last todo', 'delete_path', method: :delete %>
Here is my:
routes.rb
Rails.application.routes.draw do
get 'todos/index'
# get 'todos/delete'
match 'todos/delete' => 'todos#delete', via: :delete
Here is my:
todos_controller.rb
class TodosController < ApplicationController
def index
# #todo_array = ['Buy Milk', 'Buy Soap', 'Pay bill', 'Draw Money']
#todo_items = Todo.all
render :index
end
def delete
#put delete logic here
#todo_items = Todo.last
#todo_items.destroy
end
end
Thank you for taking the time to look at my problem!
This is how you would write a destroy method:
def destroy
#todo = Todo.last
#todo.destroy
redirect_to todos_index_path #or wherever you want to redirect user after deleting the tod
end
Also, I would simply use RESTful routes:
Rails.application.routes.draw do
resources :todos, only: %i(index destroy)
end
I seek clarification on using the thumbs up gem with rails 4. I current have a user resource and a post resource and have set up thumbs up as follows.
add gem to gemfile and installed it using bundler.
Generated require migration
User model
class User < ActiveRecord::Base
acts_as_voter
end
Post model
class Post < ActiveRecord::Base
acts_as_voteable
end
Post controller
def vote_up
#post = Post.find(params[:id])
current_user.vote_for(#post)
respond_to do |format|
format.js
end
end
View
<%= link_to('vote for this post!', vote_up_post_path(#post) , :method => :post) %>
Route file
resources :posts do
member do
post :vote_up
end
end
However i keep getting this error
No route matches [POST] "/posts/vote_up"
And after running rake routes I can see that the following route is available to me:
vote_up_post POST /posts/:id/vote_up(.:format) posts#vote_up
any ideas what could be the cause of this error ?
Could you please show us your view.
Apparently, you are calling
/posts/vote_up
instead of
/posts/:id/vote_up
"vote_up" acts like a RESTful action, similar to "post/1/delete", "post/1/edit". So you need to add this custom RESTful action in route.
Change your route like this at first.
resources :posts do
member do
post 'vote_up'
end
end
Then, in your view, to use this path, add resource as arg
vote_up_post_path #post
Reference: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
Other people reading this notes should realise that post is not a singluar of his controller posts... but the post http verb
resources :contenders do
member do
post 'vote_up'
end
end
Not sure but in your view, instead of #post try giving #post.id to vote_up_post_path.
<%= link_to('vote for this post!', vote_up_post_path(#post.id) , :method => :post) %>
I'm using a custom action to get the id of a project into the session, so that only relevant info for that project is shown in other areas. I've made a custom action in the projects controller, and am having trouble getting a link to work in the view to call that action. I just get an error saying "Couldn't find project without ID". I'm new to rails - I know it's probably an easy question, but help would be much appreciated, thanks!
View Code:
<%= link_to 'Select Project', :action => :select_project %>
Controller Code:
def select_project
#project = Project.find(params[:id])
session[:project_id] = #project.id
end
Routes:
resources :projects do
collection do
get :select_project
end
end
Alternative routes code:
resources :projects do
put 'select_project', on: :member
end
This is untested but I believe it is what you are looking for:
Routes:
resources :projects do
member do
post :set_current
end
end
this should create the following:
Endpoint: /projects/:id/set_current POST
Helper: set_current_project_path
Controller
def set_current
project = Project.find(params[:id])
session[:project_id] = project.id
redirect_to projects_path, :notice => "Current project set to #{project.name}"
end
Views
# index / erb tags excluded for simplicity
#projects.each do |project|
link_to 'Select Project', set_current_project_path(project), :method => :post
end
# show
<%= link_to 'Select Project', set_current_project_path(#project), :method => :post %>
See:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
Note also the use of 'post' instead of 'get', since we are changing the state of an object (session)
it is preferred to use a post not a get, otherwise users might pull up an old get request in the address bar
of their browser and set their session to a project unknowingly.
like varatis said - use rake routes or CONTROLLER=projects rake routes to help with determining what your route/path helpers look like and what http verbs they are expecting
And is there a reason why it's project not #project in the controller
The #project creates an instance variable; in a rails controller instance variables are made available to the views. This set_current action will never render a view, so no reason to make an instance variable out of it.
How come you have to set it to member and not collection in the routes
any action where you want to reference params[:id] should be a member route, an alternative would be to leave it as a collection route and pass params[:project_id] and pass that in all of your link_to calls, but in this case member makes more sense.
I believe resources :projects is a short cut for this break down
member do
get :show
get :edit
put :update
delete :destroy
end
collection do
get :index
get :new
post :create
end
hopefully that clarifies your questions some?
I think the route generated would be select_project_projects_path.
Link:
<%= link_to 'Select Project', select_project_projects_path %>
For future reference, run rake routes to see the automatic route helpers generated by Rails.