In my application I have a user, whose table in the database contains a boolean column for admin status. I want an admin to be able to change the admin status of any other user. The relevant view is:
<% #users.each do |user| %>
<tr>
...
<% if current_user && (current_user.id == user.id || current_user.admin) %>
...
<% if current_user.admin %>
<td><%= link_to 'Make admin', user.id.to_s + '/make_admin', {:method => 'post', :action => 'make_admin'} %></td>
<% if user.admin %>
<td><%= link_to 'Revoke admin', user.id.to_s + '/revoke_admin', {:method => 'post', :action => 'revoke_admin'} %></td>
<% end %>
...
</tr>
<% end %>
I wasn't sure how else to do it so I cobbled together the URL by concatenating the user's ID and the specific query. My controller begins with the restrictions which seem to prevent unauthorized access to these methods:
class UsersController < ApplicationController
...
before_action :admin_logged_in, only: [:edit, :update, :destroy, :make_admin, :revoke_admin]
And finally, my routing file looks like this:
Rails.application.routes.draw do
...
post ':id/make_admin' => 'users#make_admin'
post ':id/revoke_admin' => 'users#revoke_admin'
It seems to work, but I was wondering if there was a better way to do it. I've read the routing guide on Rails but little of it makes sense to me right now. I've tried linking directly to the user with
<%= link_to 'Make admin', user, {:controller => 'users', :action => 'make_admin'} %>
But I would receive an error about no route being defined for [POST]/user_id or something along those lines. That feels like the better solution in this case; if it is, what should I do in the routes.rb file to address this?
You can create your routes as follows:
resources :users do
member do
post 'make_admin', as: :make_admin
post 'revoke_admin', as: :revoke_admin
end
end
I hope this helps you out
You can add a helper to your routes like this :
post ':id/make_admin' => 'users#make_admin', as: 'make_admin'
Now make_admin_path(user.id) will link to that. You can view all helpers either by running rake routes in your site's directory or going to localhost:3000/rails/info
As for the error you got, I can't say for certain without seeing the full error, but when you <%= link_to 'text', user %> ruby interprets user at the path, and tries to find a user_path and the {:controller => 'users', :action => 'make_admin'} is a hash of HTML attributes that get added.
Related
started learning Ruby on Rails via Lynda - very excited and am trying my best to practice as much as possible. I am following the exercises but training is based on Rails 3 - through now some of the uses are not accepted.
Here is the situation:
I am reaching the create form at subjects/new
Filling out the form
get the following error in return
No route matches [POST] "/subjects/create"
Rails.root: /Users/alpozenalp/Sites/simple_cms
I spent the last 2 hours wandering around stackoverflow, rail guide and all other sources - tried many variations but can't get past this stage.
your help will be greatly appreciated.
routes.rb
SimpleCms::Application.routes.draw do
root :to => "demo#index"
get ':controller(/:action(/:id(.:format)))'
end
subjects_controller.rb
class SubjectsController < ApplicationController
def index
list
render('list')
end
def list
#subjects = Subject.order("subjects.position ASC")
end
def show
#subject = Subject.find(params[:id])
end
def new
#subject = Subject.new
end
def create
# Instantiate a new object using form parameters
#subject = Subject.new(params[:subject])
# Save the object
if #subject.save
# If save succeeds, redirect to the list action
redirect_to(:action => 'list')
else
# If save fails, redisplay the form so user can fix problems
render('new')
end
end
end
new.html.erb
<%= link_to("<< Back to List", {:action => 'list'}, :class => 'back-link') %>
<div class="subject new">
<h2>Create Subject</h2>
<%= form_for(:subject, :url => {:action => 'create'}, :method => :post) do |f| %>
<table summary="Subject form fields">
<tr>
<th>Name</th>
<td><%= f.text_field(:name) %></td>
</tr>
<tr>
<th>Position</th>
<td><%= f.text_field(:position) %></td>
</tr>
<tr>
<th>Visible</th>
<td><%= f.text_field(:visible) %></td>
</tr>
</table>
<div class="form-buttons">
<%= submit_tag("Create Subject") %>
</div>
<% end %>
</div>
naomik's answer will definitely help the form be cleaner, but it sounds like you just need to add a route for subjects in your config/routes.rb file:
SimpleCms::Application.routes.draw do
resources :subjects
root :to => "demo#index"
end
More info in the Rails routing guide.
Edit: Removed the default fallback route, per naomik's suggestion.
I have completed the course and my route.rb looks like below:
Cms2::Application.routes.draw do
root to: "public#index"
get 'admin', :to => 'access#menu'
get 'show/:id', :to => 'sections#show'
get ':controller(/:action(/:id(.:format)))'
post "admin_users/update"
post "subjects/update"
post "pages/update"
post "sections/update"
post "subjects/destroy"
post "subjects/create"
post "pages/destroy"
post "pages/create"
post "sections/destroy"
post "sections/create"
post "admin_users/destroy"
post "admin_users/create"
post "access/attempt_login"
get "access/logout"
end
My controller for def create is as follows:
def create
#new_position = params[:subject].delete(:position)
# Instantiate a new object using form parameters
#subject = Subject.new(params.require(:subject).permit(:name, :position, :visible, :created_at, :updated_at))
# Save the object
if #subject.save
##subject.move_to_position(new_position)
# If save succeeds, redirect to the list action
flash[:notice] = "Subject Created."
redirect_to(:action => 'list')
else
# If save fails, redisplay the form so user can fix problems
#subject_count = Subject.count +1
render('new')
end
end
Hope that helped!
You shouldn't have any problem if you just do
<%= form_for #subject do |f| %>
The form_for helper will automatically choose the correct (idiomatic) action and method based on the state of the model.
If #subject is a new record, you will get
<form action="/subjects" method="post">
...
If #subject is an existing record (with id: 1), you will get
<form action="/subjects/1" method="post">
<input type="hidden" name="_method" value="put">
...
Extra: Your list action seems completely pointless. Just use the index as intended.
Then this piece of code
<%= link_to("<< Back to List", {:action => 'list'}, :class => 'back-link') %>
Becomes this
<%= link_to '« Back to List'.html_safe, subjects_path, class: 'back-link' %>
I encountered the same problem at this point in the Lynda.com course. It was solved by adding resources :subjects above get ':controller(/:action(/:id(.:format)))', then changing the subjects_controller create action to
def create
#subject = Subject.new(params.require(:subject).permit(:name, :position, :visible))
if #subject.save
redirect_to(:action => 'list')
else
render('new')
end
end
This circumvented the Forbidden Attributes Error that occurred with the action as it was previously written.
Because I'd added resources :subjects, this then meant the redirect_to(:action => 'list') above would create an error along the lines of 'Couldn't find Subject with id=list'. To fix this, I added get 'subjects/list' => 'subjects#list' above the resources :subjects route (I've no idea if this was the 'right' thing to do, but it works for now).
I have a rails 3 app, and when I click the link to my terms page, it routes to a completely different controller, than what the routes should use. Stranger still, the route works when I'm not logged in, and I'm using devise.
I get this error when clicking the link when I'm logged in.
No route matches {:action=>"edit", :controller=>"users", :id=>nil}
<%= link_to "Terms", terms_path %>
Routes (in the order they appear in routes.rb):
devise_for :users, :controllers => {:registrations => "registrations"}
resources :users do
member do
get :following, :followers
post :accept
end
end
match '/terms', to: 'static_pages#user_agreement'
Static Pages Controller
def user_agreement
end
Rake Routes
terms /terms(.:format) static_pages#user_agreement
This also happens for every other action that I've routed this way to the staticpages controller, but not for any other actions that route to different controller.
Update: Terms Page
Header:
<%= link_to "Follow", users_path %>
<%= link_to current_user.name, current_user %>
<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
Footer:
<%= link_to "Welcome", welcome_path %>
<%= link_to "Settings", edit_user_path(#user) %>
<%= link_to "Terms", terms_path %>
All the content is pure html.
Thanks in advance
You have a link to edit_user_path with no #user as hinted in the comments.
You should almost certainly be using current_user anyway.
This question already has answers here:
Path helpers generate paths with dots instead of slashes
(3 answers)
Closed 8 years ago.
I have installed Devise (called members) and have set up some custom routes so that I can spit out all the members and allow them to have their own page (/memebers/ and /members/:id/)
However in my view file for the members index when passing the route members_path(member_id) it is outputting members.1 instead of members/1
Code below:
index view:
<% #members.each do |member| %>
<tr>
<td><%= link_to member.name, members_path(member.id) %></td>
<td><%= member.email %></td>
<td><%= member.id %></td>
<td><%= member.admin %></td>
</tr>
<% end %>
Routes:
devise_for :members
match 'members/' => 'members#index'
match 'members/:id' => 'members#show'
Members Controller:
class MembersController < ApplicationController
def index
#members = Member.all
respond_to do |format|
format.html # show.html.erb
format.json { render json: #student }
end
end
def show
#member = Member.find(params[:id])
end
end
Rake Routes:
members /members(.:format) members#index
/members/:id(.:format) members#show
Any help? Cheers :)
Had to add
, as: :show_member
so in my routes file I had to define a path for that
match 'members/:id/' => 'members#show', as: :show_member
and adding this in the index view file:
show_member_path(member)
and rake routes is now:
members GET /members(.:format) members#index
show_member GET /members/:id(.:format) members#show
Cheers :)
This is not the helper method you are looking for. members_path creates a path to members#index and takes format as its only argument.
The helper that links to members#show is member_path. Although, it's not automatically created by match:
# config/routes.rb
resources :members, only: [:index, :show]
# Remove `only` to get the remaining restful routes
# and in your view:
<%= link_to member.name, member_path(member.id) %>
You can also just pass in the member itself and link_to will automatically call to_param, which returns id by default:
<%= link_to member.name, member_path(member) %>
Alternatively, you can just pass in your member directly with no path helper:
<%= link_to member.name, member %>
Read more here: http://guides.rubyonrails.org/routing.html
My route.rb:
map.resources :car_users
car_users_controller.rb:
class CarUsersController < ApplicationController
def index
#car_users = CarUsers.all
end
def show
end
def delete
redirect_to :car_users_path
end
end
I created a delete link in index view:
...
<% #car_users.each do |car_usr| %>
<tr>
<td>
link_to "DELETE IT", delete_car_user_path(car_usr.id)
</td>
</tr>
...
But I got the error:
undefined method `delete_car_user_path' for #<ActionView::Base:0x9d17b40>
Why?
(I am working with Rails v2.3.2)
Because delete_car_user_path isn't a route and I assume you haven't defined it anywhere. If you want a delete link use:
link_to "DELETE IT", car_user_path(car_usr), :method => :delete, :confirm => 'Are you sure ?'
For future reference use rake routes on the command line to get a list of routes.
I do remember an instructor on Lynda.com saying that for whatever reason Rails (I'm on 4.2) does not implement the DELETE route. I feel like there has to be a better way to do this but this worked for me (using RESTful routes):
<%= link_to "DELETE IT", "car_users/#{car_usr.id}/delete", method: :get %>
I am new to Rails and I'm I am trying to create a basic blog application, but I'm having trouble linking.
I have three controllers (authors, pages and static_pages). They all work fine but I'm trying to link to two pages in static_pages. They are about.html.erb and help.html.erb. I'm using a partial to create a navigation menu at the top.
I'm getting the following error:
ActionController::RoutingError in Pages#index
No route matches {:controller=>"pages", :action=>"about"}
1: <%= link_to 'Homepage', pages_path %> |
2: <%= link_to 'List of Authors', authors_path %> |
3: <%= link_to 'About', :action => 'about' %> |
4: <%= link_to 'Help', :action => 'help' %>
The code in my menu partial is:
<%= link_to 'Homepage', pages_path %> |
<%= link_to 'List of Authors', authors_path %> |
<%= link_to 'About', :action => 'about' %> |
<%= link_to 'Help', :action => 'help' %>
My static_pages controller looks like this:
class StaticPagesController < ApplicationController
def About
end
def Help
end
end
I understand that it's probably something very simple but as I say I'm new to Rails and web development in general so any advice will be appreciated.
Trivial, make your action methods lowercase. Ruby is case sensitive with variable and method names.
class StaticPagesController < ApplicationController
def about
end
def help
end
end
Have you checked your routes using rake routes in your terminal/console? If not this is a good way to solve problems related to route errors.
Make sure that your link_to methods are trying to access the StaticPagesController, your error seems to indicate that Rails is trying to create the URL for the about action through PagesController.
Check the docs for ActionView::Helpers::UrlHelper, especially the link_to and url_for methods.