Rails Routes.rb - ruby-on-rails

How does rails know how to map to each function in the controller if the routes.rb file only specifies:
resources :users
but inside the UsersController you have
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, :notice => 'User was successfully created.' }
format.json { render :json => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
How does rails determine that for instance the index function maps to GET/users while the create function maps to POST/users?
How does resources :users even know to map to the UsersController?

Rails is based around the 'convention over configuration' paradigm.
As such, the "resources :users" line indicates that all the standard CRUD methods are supported by the corresponding UsersController <-- the 'Users' prefix matches to the Controller, Model etc.

Please check the rails routes guide: http://guides.rubyonrails.org/routing.html
And to see in practice what the routes declaration does issue this command in your project directory:
rake routes
Also as mentioned before, stick with conventions and remember that rails is a very opinionated piece of software.

Related

Ruby on Rails API how to soft delete an user

I am able to soft delete an user from the main application.
Here are the details.
The user URL is:
http://0.0.0.0:3000/users/4c7fa12c-3d58-480b-a823-6c67d6e7f0fe.json
Which is presenting a JSON result like this:
{"id":"4c7fa12c-3d58-480b-a823-6c67d6e7f0fe","name":"John","status":"Active","created_at":"2015-11-10T18:31:27.000+00:00","updated_at":"2015-11-10T18:38:20.000+00:00"}
I can do a soft delete by using an inactivation this way:
http://0.0.0.0:3000/users/4c7fa12c-3d58-480b-a823-6c67d6e7f0fe/inactivate
Here is my inactivate method in the users controller:
def inactivate
#user.update status: 'Inactive'
redirect_to users_url
end
The result is shown when reload the user URL:
{"id":"4c7fa12c-3d58-480b-a823-6c67d6e7f0fe","name":"John","status":"Inactive","created_at":"2015-11-10T18:31:27.000+00:00","updated_at":"2015-11-10T19:29:58.000+00:00"}
Now my user is "Inactive".
Here is my routes file:
Rails.application.routes.draw do
resources :wit_dims
resources :wokas
resources :posts
resources :languages
resources :users
root :to => "home#index"
resources :users do
get 'inactivate', on: :member
end
match 'inactivate', to: 'users#inactivate', via: 'delete'
#api
namespace :api do
namespace :v1 do
resources :users, only: [:index, :create, :show, :update, :destroy]
resources :posts, only: [:index, :create, :show, :update, :destroy]
end
end
end
How I can change this routes file and the API users controller to make the same king of inactivation through the API? I want more than a trivial solution using a PUT to change status of the user from Active to Inactive.
Here is my main application users controller:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :inactivate]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully inactivated.' }
format.json { head :no_content }
end
end
def inactivate
#user.update status: 'Inactive'
redirect_to users_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params[:user]
end
end
Here is my API users controller:
class Api::V1::UsersController < Api::V1::BaseController
before_action :set_user, only: [:show, :update, :destroy]
def show
render(json: Api::V1::UserSerializer.new(#user).to_json)
end
def update
if #user.update_attributes(user_params)
render(
json: Api::V1::UserSerializer.new(#user).to_json,
status: 200,
location: api_v1_user_path(#user.id)
)
else
return api_error(status: 422, errors: #tbm.errors)
end
end
def index
users = User.all
render(
json: ActiveModel::ArraySerializer.new(
users,
each_serializer: Api::V1::UserSerializer,
root: 'users'
)
)
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, :status).delete_if{ |k,v| v.nil? }
end
end
Basically I would like to be able to call an inactivate method through the API which is going to change the status from Active to Inactive, instead of physically deleting / destroying the user.
I used PUT and executed an updated on the status attribute to mark the user as Inactive.

NoMethodError Rails 3.2

I've been searching all over and can't find the answer to this anywhere.
I'm taking the intro to RoR course on udemy, and I've been able to solve all the problems I've had in the first 80% of the course, but now I'm at a roadblock and can't find this. We're building an app like Etsy, and I'm at the point where I need to restrict users from editing/deleting listings that don't belong to them.
I'm running Ruby 1.9.3 on Rails 3.2.21
I tried following the instructions for adding the check user filter, but when I checked back on local host, I received this error:
NoMethodError in ListingsController#edit
undefined method `user' for nil:NilClass
app/controllers/listings_controller.rb:98:in `check_user'
Parameters:
{"id"=>"8"}
My code matches the instructor's code exactly, but I think this error is because I'm using Rails 3, and he's using 4.
Here's my listings_controller.rb
class ListingsController < ApplicationController
# GET /listings
# GET /listings.json
before_filter :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
before_filter :check_user, only: [:edit, :update, :destroy]
def index
#listings = Listing.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #listings }
end
end
# GET /listings/1
# GET /listings/1.json
def show
#listing = Listing.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #listing }
end
end
# GET /listings/new
# GET /listings/new.json
def new
#listing = Listing.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #listing }
end
end
# GET /listings/1/edit
def edit
#listing = Listing.find(params[:id])
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(params[:listing])
#listing.user_id = current_user.id
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render json: #listing, status: :created, location: #listing }
else
format.html { render action: "new" }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PUT /listings/1
# PUT /listings/1.json
def update
#listing = Listing.find(params[:id])
respond_to do |format|
if #listing.update_attributes(params[:listing])
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing = Listing.find(params[:id])
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url }
format.json { head :no_content }
end
end
private
def set_listing
#listing = Listing.find(params[:id])
end
def listing_params
params.require(:listing).permit(:name, :description, :price, :image)
end
def check_user
if current_user != #listing.user
redirect_to root_url, alert: "Sorry, this listing belongs to someone else."
end
end
end
The code that we had to add for this is the second before_filter and the def check_user
If any other information is needed to help answer this, please let me know.
It's not a Rails 3 vs 4 issue, your code never calls set_listing and so #listing is never being set. You should probably have a:
before_filter :set_listing, only: [:show, :edit, :update, :destroy]
at the top of your file, before the before_filter :check_user, ...

How to resolve "ActiveModel::ForbiddenAttributesError" Error

I got the following error when I clicked on the "Create user" button.
Error:
ActiveModel::ForbiddenAttributesError
Extracted source (around line #27):
25 # POST /users.json
26 def create
27 #user = User.new(params[:user])
28 respond_to do |format|
29 if #user.save
I am following the below reference link and typed same command and same code given.
http://railscasts.com/episodes/206-action-mailer-in-rails-3?view=asciicast
My code snippets are described below.
In app/controller/user_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
UserMailer.registration_confirmation(#user).deliver
format.html { redirect_to(#user, :notice => 'User was successfully created.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email)
end
end
In config/initializer/setup_mail.rb
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "gmail.com",
:user_name => "w5call.w5rtc#gmail.com",
:password => "w5rtc123#",
:authentication => "plain",
:enable_starttls_auto => true
}
In app/mailer/user_mailer.rb
class UserMailer < ActionMailer::Base
default :from => "w5call.w5rtc#gmail.com"
def registration_confirmation(user)
mail(:to => user.email, :subject => "Registered", :from => "w5call.w5rtc#gmail.com")
end
end
app\views\user_mailer\registration_confirmation.text.erb
<%= #user.name %>,
Thank you for registering!
Please help me for resolve this error as i am totaly new to ROR. Thanks in Advance.
In Rails 4 there is concept of Strong Parameter.
Strong Parameter in rails
To fixed this issue you need to change you create method and call #user = User.new(user_params) methods instead.
Change
def create
#user = User.new(params[:user])
to
def create
#user = User.new(user_params)

ActiveModel::MassAssignmentSecurity

I get a ActiveModel::MassAssignmentSecurity::Error when I try to running my app to save the login and password details.
got the following error
Can't mass-assign protected attributes: name, password, password_confirmation, salt
app/controllers/users_controller.rb:43:in new'
app/controllers/users_controller.rb:43:increate'
here is the code from the control file
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
Answer in Stack Overflow and credits for Damien Mathieu
In your model, you need to add tag_attributes to the attr_accessible call.
For example :
class User < ActiveRecord::Base
attr_accessible :tags_attributes
end
If you already call it once, you can either add this field as an argument of the method, or make a second call. Both options are equivalent.
Having to specify all accessible parameters wasn't a default until a few months.
This guide has been updated to reflect the change of default. But the new version hasn't been deployed yet, this is why it's not specified.
I think you forgot to add the attr_accessible parameters in your model. Check out Rails API for more information regarding attr_accessbile and what it protects from.
Like waldyr.ar said, also you can use attr_protected

Unable to create a REST API for my RoR app

I am trying to create a REST API for my app.
The map.connect_resource :book causes the following error, when executing rake test:functionals:
Error: undefined local variable or method `map' for #
<ActionDispatch::Routing::Mapper:0x8a11e74>.
In my app, I'm trying to implement RoR with MySQL with the following table data.
Table Name: Object
Fields: object_id, Object_name, Object_description etc...
I would like to create a REST API object for querying the above database and retrieving the data. What's the best way to proceed?
That is a reallyyyyyyy old tutorial (from 6 years ago!!!). I would recommend reading this guide instead: http://guides.rubyonrails.org/routing.html
Assuming you are running Rails 3, you should just put this in your routes.rb file:
resources :books
That will expose routes for your BooksController so you can access:
HTTP Verb Path action used for
-----------------------------------------------------------------------
GET /books index display a list of all books
GET /books/new new return an HTML form for creating a new book
POST /books create create a new book
GET /books/:id show display a specific book
GET /books/:id/edit edit return an HTML form for editing a book
PUT /books/:id update update a specific book
DELETE /books/:id destroy delete a specific book
So in your BooksController you would then have:
class BooksController < ApplicationController
# GET /books
# GET /books.xml
def index
#books = Book.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #books }
end
end
# GET /books/1
# GET /books/1.xml
def show
#book = Book.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #book }
end
end
# GET /books/new
# GET /books/new.xml
def new
#book = Book.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #book }
end
end
# GET /books/1/edit
def edit
#book = Book.find(params[:id])
end
# POST /books
# POST /books.xml
def create
#book = Book.new(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
# PUT /books/1
# PUT /books/1.xml
def update
#book = Book.find(params[:id])
respond_to do |format|
if #book.update_attributes(params[:book])
format.html { redirect_to(#book, :notice => 'Book was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.xml
def destroy
#book = Book.find(params[:id])
#book.destroy
respond_to do |format|
format.html { redirect_to(books_url) }
format.xml { head :ok }
end
end
end

Resources