I use the following routes configuration in a Rails 3 application.
# config/routes.rb
MyApp::Application.routes.draw do
resources :products do
get 'statistics', on: :collection, controller: "statistics", action: "index"
end
end
The StatisticController has two simple methods:
# app/controllers/statistics_controller.rb
class StatisticsController < ApplicationController
def index
#statistics = Statistic.chronologic
render json: #statistics
end
def latest
#statistic = Statistic.latest
render json: #statistic
end
end
This generates the URL /products/statistics which is successfully handled by the StatisticsController.
How can I define a route which leads to the following URL: /products/statistics/latest?
Optional: I tried to put the working definition into a concern but it fails with the error message:
undefined method 'concern' for #<ActionDispatch::Routing::Mapper ...
I think you can do it by two ways.
method 1:
resources :products do
get 'statistics', on: :collection, controller: "statistics", action: "index"
get 'statistics/latest', on: :collection, controller: "statistics", action: "latest"
end
method 2, if you have many routes in products, you should use it for better organized routes:
# config/routes.rb
MyApp::Application.routes.draw do
namespace :products do
resources 'statistics', only: ['index'] do
collection do
get 'latest'
end
end
end
end
and put your StatisticsController in a namespace:
# app/controllers/products/statistics_controller.rb
class Products::StatisticsController < ApplicationController
def index
#statistics = Statistic.chronologic
render json: #statistics
end
def latest
#statistic = Statistic.latest
render json: #statistic
end
end
Related
I want to implement on Angular 2 pagination but I do not know how to write in controller and in routes on rails. Who can explain how to write controller and routes correctly?
Here is part of my code controller and routes:
Controller:
...
def index
#spr_bit_types = SprBitType.all
render json: #spr_bit_types
end
def show
render json: #spr_bit_type
end
def page
#page = params [: page]
#pre_page = params [: pre_page]
end
...
Routes.rb:
Rails.application.routes.draw do
resources :spr_bit_types, only: [:index, :create, :update, :destroy]
map.connect 'spr_bit_types / page /: page',: controller => 'spr_bit_types',: action =>' page '
...
end
This part of the code does not work at all: map.connect 'spr_bit_types / page /: page',: controller => 'spr_bit_types',: action =>' page '
Use api-pagination gem
and then you can simply write following code
def index
#spr_bit_types = SprBitType.all
paginate json: #spr_bit_types
end
def show
paginate json: #spr_bit_type
end
I have a ReportsController, nested in ProjectsController, with a #show method:
def show
# Some stuff
do_something(#report)
end
Routes:
resources :projects do
resources :reports
end
I need to test that the do_something method is called:
it 'calls do_something' do
expect(controller).to receive(:do_something)
project = create :project
report = create :report, project: project
get :show, params: {project_id: project.id, id: report.id}
end
I placed binding.pry within the #show action, but this doesn't get called. So what's wrong with my spec?
The problem was that I wasn't logged in:
before do
#user = create :user, :admin
sign_in_as #user
end
I am getting a routing error when I attempt to create a new db entry or update a current one.
ERROR: No route matches [POST] "/pubs"
Routes.rb:
resources :people, except: [:show] do
resources :pubs, except: [:create, :new, :edit, :destroy]
end
resources :articles
resources :pubs, except: [:create, :new, :edit, :destroy]
namespace :sekret do
resources :people do
resources :pubs
end
end
sekret/pubs_controller
class Sekret::PubsController < SekretController
def index
#pubs = Pub.all
end
def show
#pub = Pub.find(params[:id])
end
def new
#person = Person.find(params[:person_id])
#pub = #person.pubs.new
end
def create
#pub = Pub.new(pub_params)
if #pub.save
flash[:notice] = "Article created successfully!"
redirect_to sekret_person_pub_path(#pub)
else
render :new, status: :unprocessable_entity
end
end
def edit
#pub = Pub.find(params[:id])
end
def update
#pub = Pub.find(params[:id])
if #pub.update(pub_params)
redirect_to sekret_person_pub_path(#pub)
else
render :edit, status: :unprocessable_entity
end
end
def destroy
pub = Pub.find(params[:id])
pub.destroy
redirect_to sekret_people_path
end
private
def pub_params
params.require(:pub).permit(
:pubmed_id, :journal, :pages, :date, :type, :link, :authors,
:title, :notes, :auth_id, :person_id)
end
end
After going through all of this setup, when I allow the non-namespace pubs to resolve edit, update, etc, the update process goes through without a hitch. Once I limit these functions to within the password protected namespace I get the routing error. After parsing through the routes I can see that sekret_person_pub_path is listed there. I think I am missing something somewhere.
Rake Routes:
pubs#index
pub GET /pubs/:id(.:format) pubs#show
PATCH /pubs/:id(.:format) pubs#update
PUT /pubs/:id(.:format) pubs#update
sekret_person_pubs GET /sekret/people/:person_id/pubs(.:format) sekret/pubs#index
POST /sekret/people/:person_id/pubs(.:format) sekret/pubs#create
new_sekret_person_pub GET /sekret/people/:person_id/pubs/new(.:format) sekret/pubs#new
edit_sekret_person_pub GET /sekret/people/:person_id/pubs/:id/edit(.:format) sekret/pubs#edit
sekret_person_pub GET /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#show
PATCH /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#update
PUT /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#update
DELETE /sekret/people/:person_id/pubs/:id(.:format) sekret/pubs#destroy
sekret_people GET /sekret/people(.:format)
By using resources :pubs, except: [:create, :new, :edit, :destroy], you are preventing the route generation from providing POST /pubs.
The namespace and nested resources will generate a URL POST sekret/people/:person_id/pubs.
In your controller, you should create the Pub as an associated object.
def create
person = Person.find(params[:person_id])
#pub = person.pubs.new(pub_params)
if #pub.save
flash[:notice] = "Article created successfully!"
redirect_to sekret_person_pub_path(#pub)
else
render :new, status: :unprocessable_entity
end
end
If you want to restrict access the create method, you could use an authorization library such as Pundit in which case you would setup a policy to restrict who can do what.
https://github.com/elabs/pundit
You are missing out on the routes because rails form don't use the correct routes when namespacing so you'll have to specify them manually
<%= form for #pub, url: sekret_person_pubs_path do |f| %>
to let the form knows which route to post, if you do not specify the url, rails will use url: person_pubs_path behind the scenes
Edit: forgot to add _path
I have a resource named Volunteers:
class VolunteersController < ApplicationController
before_filter :authenticate_user!
def index
##volunteers = Volunteer.all()
#volunteers = Volunteer.paginate(:page => params[:page])
end
def show
#volunteer = Volunteer.find(params[:id])
end
def new
#volunteer = Volunteer.new
end
def create
#post = Volunteer.new(volunteer_params)
#post.save
redirect_to #post
end
def destroy
#volunteer = Volunteer.find(params[:id])
#volunteer.destroy
redirect_to :action => 'index'
end
def search
#volunteers = Volunteer.search params[:search]
end
private
def volunteer_params
params.require(:volunteer).permit(:forename, :surname)
end
end
I have added an additional action called search but I'm having issues mapping it in my routes file:
root 'home#index'
resources :volunteers
How do I map to the search action (including params)?
There is an example in the route file itself:
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
You need to add the search method as a post (or whatever is appropriate) option for the resource, you can either add it to collection or member - collection methods won't look for a specific item id in the url, which is appropriate for a search method.
resources :volunteers do
collection do
post :search
end
end
I have written a simple API but something feels wrong about the routes and the APIs. Its my first time am writing an API and just a few months writing ROR code. Take a look at the code below and help me straighten it!!
I wish the API to respond to requests like https://api.xxxxx.com/v1/xml?username=u_name&password=passwd& to=xxxxx&from=xxxx&message=text
The subdomain does not seem to be working either;
Routes
namespace :api, :path => "", constraints: {subdomain: 'api'} do
namespace :v1 do
namespace :json, defaults: {format: :json} do
resources :messages
resources :balance
end
namespace :xml, defaults: {format: :xml} do
resources :messages
resources :balance
end
end
end
These are the controllers for the json API
Messages Controller:
class Api::V1::Json::MessagesController < ApplicationController
before_filter :authenticate
def show
end
def create
#user = current_user
#message = Message.new(params[:message])
if #message.save
MessageWorker.perform_async(#message.id, lists, current_user.id)
render json: {status: "success", to: #message.count, from: #message.from,
balance: #user.balance, message: #message.message},
time: #message.created_at}
else
render status: 400
end
end
def authenticate
authenticate_or_request_with_http_basic do |username,password|
resource = User.find_by_email(username)
if resource.valid_password?(password)
sign_in :user, resource
end
end
end
end
Balance Controller:
class Api::V1::Json::BalanceController < ApplicationController
before_filter :authenticate
def show
#balance = current_user.balance
render json: {user: current_user.name.titleize, balance: "#{current_user.currency}: #{#balance}"}
end
def authenticate
authenticate_or_request_with_http_basic do |username,password|
resource = User.find_by_email(username)
if resource.valid_password?(password)
sign_in :user, resource
end
end
end
end
Do:
constraints subdomain: 'api' do
scope module: :api do
namespace :v1 do
You'd rather not namespace json or xml, it makes no sense: the same controllers should handle both request, just a matter of format.
Rails makes it really easy with respond_to