Let's say I want to support both GET and POST methods on the same URL. How would I go about handling that in a rails controller action?
You can check if it was a post using request.post?
if request.post?
#handle posts
else
#handle gets
end
To get your routes to work:
resources :photos do
member do
get 'preview'
post 'preview'
end
end
Here's another way. I included example code for responding with 405 for unsupported methods and showing supported methods when the OPTIONS method is used on the URL.
In app/controllers/foo/bar_controller.rb
before_action :verify_request_type
def my_action
case request.method_symbol
when :get
...
when :post
...
when :patch
...
when :options
# Header will contain a comma-separated list of methods that are supported for the resource.
headers['Access-Control-Allow-Methods'] = allowed_methods.map { |sym| sym.to_s.upcase }.join(', ')
head :ok
end
end
private
def verify_request_type
unless allowed_methods.include?(request.method_symbol)
head :method_not_allowed # 405
end
end
def allowed_methods
%i(get post patch options)
end
In config/routes.rb
match '/foo/bar', to: 'foo/bar#my_action', via: :all
Just need to use this, to use only get and post in the same route
resources :articles do
member do
match 'action_do-you_want', via: [:get, :post]
end
end
you can try this
match '/posts/multiple_action', to: 'posts#multiple_action', via: [:create, :patch, :get, :options]
I would say, the best way is to create separate actions in the controller and state them in routes.
# config/routes.rb
...
get '/my_action' => 'my#my_action_get'
post '/my_action' => 'my#my_action_post'
...
# app/controllers/my_controller.rb
...
def my_action_get
# do stuff like listing smth
end
def my_action_post
# do other stuff
end
In fact, the same logic is used by Rails by default: index and create actions are both called by requests sent to the same paths (e.g. /articles), however, they have different request methods: GET /articles request is redirected to the index action and lists all articles, and POST /articles is redirected to the create action and creates a new article.
This works for me:
In routes.rb
Rails.application.routes.draw do
post '/posts', to: 'posts#create'
get '/posts', to: 'posts#list_all'
end
In posts_controller.rb
class PostsController < ApplicationController
def create
new_post = Post.create( content: params[:content], user_id: params[:user_id] )
render json: { post: new_post }
end
def list_all
request = Post.all
render json: { all_posts: request }
end
end
So each action is referred to a different function
Related
I have a Subscriber model that takes in a "phone_number" and a "visit" integer. I have two controllers Subscribers and Visits(super and sub) I have never worked with nested controllers before and I'm having some issues with namespace I believe. Because I getting back the uninitialized constant error. Basically the subscriber controller signs up a subscriber and the visit controller counts the amount of times they've visited by user input of their phone_number. Why am I getting this error? I'll show my code for clarity.
CONTROLLERS
class Subscribers::VisitsController < ApplicationController
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.find_by_phone_number(params[:phone_number])
if #subscriber
#subscriber.visit += 1
#subscriber.save
redirect_to subscribers_visits_new_path(:subscriber)
else
render "new"
end
end
end
class SubscribersController < ApplicationController
def index
#subscriber = Subscriber.all
end
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.create(subscriber_params)
if #subscriber.save
flash[:success] = "Subscriber Has Been successfully Created"
redirect_to new_subscriber_path(:subscriber)
else
render "new"
end
end
ROUTES
Rails.application.routes.draw do
devise_for :users
resources :subscribers, except: :show
get '/subscribers/visits/new', to: 'subscribers/visits#new'
root "welcomes#index"
VIEWS
<h1>hey</hey>
<%= form_for #subscriber do |form| %>
<div class="form-group">
<p>
<%= form.label :phone_number %>
<%= form.text_field :phone_number %>
</p>
<% end %>
ERROR
Hmm, my guess is you are trying to route url subscriber/visits/new to new action in VisitsController?How about changing this line:
get '/subscribers/visits/new', to: 'subscribers/visits#new'
to:
namespace :subscribers do
get '/visits/new', to: 'visits#new'
end
Also try to move this block above resources :subscribers, except: :show if you still get the error.
Cheers
You probably do not need to inherit one controller from another. Simply define the controllers as you normally would:
app/controllers/subscribers_controller.rb
class SubscribersController < ApplicationController
# methods for Subscribers
end
in app/controllers/visits_controller.rb
class VisitsController < ApplicationController
# methods for Visits
end
Note that these must to be located in separate files, so that Rails can find the correct source file by the name of the object that it's looking for. This is a Rails naming convention.
Regarding your routes, you'll need to change to use one of 4 route formats. Reading the section on Adding More RESTful Actions in the Rails Routing from the Outside In guide might help.
1) To route visits as a nested resource, which is what it appears you're actually trying to do, you would use this:
resources :subscribers, except: :show do
resources :visits
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/:id/visits/new
POST /subscribers/:id/visits
GET /subscribers/:id/visits
GET /subscribers/:id/visits/:id
GET /subscribers/:id/visits/:id/edit
PATCH /subscribers/:id/visits/:id/update
DELETE /subscribers/:id/visits/:id/destroy
This is the typical route structure for nested resources and separate controllers.
2) To make visits#new a simple collection (non-member) action in the VisitsController, then you likely want this:
resources :subscribers, except: :show do
collection do
get 'visits/new', to 'visits#new'
post 'visits', to 'visits#create'
end
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/visits/new
POST /subscribers/visits
This is typically used to add new top-level routes in an existing resource and controller.
3) To construct visits as member actions, use this:
resources :subscribers, except: :show do
member do
get 'visits/new', to 'visits#new'
post 'visits', to 'visits#create'
end
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/:id/visits/new
POST /subscribers/:id/visits
This is normally used to add new member routes in an existing resource and controller.
4) To simply make visits routes appear to be included in subscribers, you could use this:
get '/subscribers/visits/new', to: 'visits#new'
post '/subscribers/visits', to: 'visits#create'
resources :subscribers, except: :show
This will produce these routes:
GET /subscribers/visits/new
POST /subscribers/visits
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
This may be used to make arbitrary routes appear to be included in an existing resource, when they really may be independent.
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
How to load routes from database?
I have table Post with column :url. There is part of the url in this column, e.g.:
about
progs/us
progs/us/info
empty
etc.
How to set routes for this? Result example:
http://mysite.com/progs/us for the page http://mysite/posts/2
You can intercept any url by this route:
# routes.rb
get '*url' => 'posts#show', format: false
Note: this route should be declared last in your config
And controller looks like following:
# posts_controller.rb
class PostsController < ApplicationController
def show
#post = Post.find_by_url!(params[:url])
# by default "show" view is rendered with "post" variable
end
end
Here's how I made routes like this
www.example.com/jenny250
www.example.com/bob1985
At end of routes.rb
get ':username' => 'users#show'
In the users controller
def show
#user = User.find_by_username(params[:username])
# ...
end
I have a has many through association.
Firms have many Users through Follows.
I want Users to be able to Follow Firms. - I am using Devise for the users.
I have the following action in my firms controller.
def follow
#firm.users << current_user
end
in my routes.rb
resources :firms do
post :follow, on: :member
end
and in my firms view
<%= link_to "Follow", follow_firm_path(#firm), method: :post %>
However when I keep getting the following Routing Error in the browser
No route matches {:action=>"follow", :controller=>"firms"}
Rake Routes confirms the following
follow_firm POST /firms/:id/follow(.:format) firms#follow
Any ideas what the problem may be?
Many thanks
Edit: Controller code
class FirmsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
def index
#firm_names = Firm.all.map &:name
direction = params[:direction]
direction ||= "ASC"
#firms = Firm.order("name #{direction}")
respond_to do |format|
format.html # index.html.erb
format.js
end
end
def follow
#firm.users << current_user
end
I am using the follow action in a partial in the index view.
everything looks good and this should work perfectly. Except that I see a typo in the following line
<%= link_to "Follow", follow_firm_path(#firm), method: :post %>
after the :method there should an => not a : . this will make the link a get request not a post request, that might be the issue, try using a simple link and replace post will get in your routes.rb just to test if the issue is arising due to this.
you can also test route methods from the console
rails c
app.follow_firm_path(2)
I noticed you also have an error in your routes, there should be an => not a : after :on
resources :firms do
post :follow, :on => member
end
You should define methods like this...
resources :firms do
collection
post :follow, on: :member
end
end
I think if this method does not create anything its type should be get.
Try it
I am trying to redirect user to show_city_url or show_city_path but i get an exception that they are both undefined.In the city controller i have three actions show,like, and dislike. unlike_city_path and like_city_path works but show_city_path doesnt.Also when i put this in all_cities action redirect_to :controller=>"city",:action=>"show" works.What am i doing wrong?Thank you.
class HomeController < ApplicationController
def all-cities
redirect_to show_city_url
end
end
In the Routes
resources :city do
member do
post :like
post :dislike
get :show
end
end
according to your comments:
resources :cities, :controller => 'city' do
collection do
get :show, :as => :show
end
member do
post :like
post :dislike
end
end
now you can call show_cities_url and you'll land in the show action of your CityController.
PS: Following the Rails' convention makes your life easier ;)
RoR Guide: Rails Routing from the Outside In