What's the equivalent of rake routes in Phoenix? - phoenix-framework

Ruby on Rails comes with the terminal command rake routes. Is there an equivalent in Phoenix?

The command is $ mix phoenix.routes

As #Martimatix pointed out $ mix phx.routes print all routes for the default router, here's the documentation
This is an example of routes generated for this router.ex file:
defmodule MessageApi.Router do
use MessageApi.Web, :router
pipeline :api do
plug :accepts, ["json"]
end
scope "/api", MessageApi do
pipe_through :api
resources "/messages", MessageController, except: [:new, :edit]
resources "/message_details", MessageDetailController, except: [:new, :edit]
end
end
then routes generated will be:
message_path GET /api/messages MessageApi.MessageController :index
message_path GET /api/messages/:id MessageApi.MessageController :show
message_path POST /api/messages MessageApi.MessageController :create
message_path PATCH /api/messages/:id MessageApi.MessageController :update
PUT /api/messages/:id MessageApi.MessageController :update
message_path DELETE /api/messages/:id MessageApi.MessageController :delete
message_detail_path GET /api/message_details MessageApi.MessageDetailController :index
message_detail_path GET /api/message_details/:id MessageApi.MessageDetailController :show
message_detail_path POST /api/message_details MessageApi.MessageDetailController :create
message_detail_path PATCH /api/message_details/:id MessageApi.MessageDetailController :update
PUT /api/message_details/:id MessageApi.MessageDetailController :update
message_detail_path DELETE /api/message_details/:id MessageApi.MessageDetailController :delete

Related

How to check the arguments of the auto generated Phoenix paths

No helper clause for Api.Router.Helpers.v1_user_organization_path
defined for action :show with arity 3. Please check that the function,
arity and action are correct. The following v1_user_organization_path
actions are defined under your router:
* :create
* :index
* :show
* :update
router.ex
defmodule Api.Router do
use Api.Web, :router
pipeline :api do
plug :accepts, ["json"]
end
scope "/", Api do
pipe_through :api
end
scope "/v1", Api.V1, as: :v1 do
pipe_through :api
resources "/users", UserController, only: [:create, :show, :update] do
resources "/organizations", OrganizationController, only: [:create, :update, :index, :show]
end
end
end
and when I do mix phoenix.routes I see the following v1_user_organization_path getting generated. The problem is I don't know how to use it and I don't know what I should pass into it. Is there a way I can check what this generated method accepts?
The error I get is occuring here
organization_controller.ex
def create(conn, %{"user_id" => user_id, "organization" => organization_params}) do
changeset = Organization.changeset(%Organization{}, organization_params)
case Repo.insert(changeset) do
{:ok, organization} ->
conn
|> put_status(:created)
|> put_resp_header("location", v1_user_organization_path(conn, :show, organization))
|> render("show.json", organization: organization)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(Api.ChangesetView, "error.json", changeset: changeset)
end
end
At put_resp_header("location", v1_user_organization_path(conn, :show, organization))
You can look at the auto generated documentation for the router helper functions using h in iex -S mix and reading the output of mix phoenix.routes for some help. For example, for the following routes:
resources "/posts", PostController do
resources "/comments", CommentController
end
I get:
iex(1)> h MyApp.Router.Helpers.post_comment_path
def post_comment_path(conn_or_endpoint, action, post_id)
def post_comment_path(conn_or_endpoint, action, post_id, params)
def post_comment_path(conn_or_endpoint, action, post_id, id, params)
$ mix phoenix.routes
post_comment_path GET /posts/:post_id/comments MyApp.CommentController :index
post_comment_path GET /posts/:post_id/comments/:id/edit MyApp.CommentController :edit
post_comment_path GET /posts/:post_id/comments/new MyApp.CommentController :new
post_comment_path GET /posts/:post_id/comments/:id MyApp.CommentController :show
post_comment_path POST /posts/:post_id/comments MyApp.CommentController :create
post_comment_path PATCH /posts/:post_id/comments/:id MyApp.CommentController :update
PUT /posts/:post_id/comments/:id MyApp.CommentController :update
post_comment_path DELETE /posts/:post_id/comments/:id MyApp.CommentController :delete
It's not clear from just the function signature which action accepts how many arguments, but if you read the output of mix phoenix.routes, you can see that :show (last column) requires a post_id and an id.
The output of h is also not completely accurate because it doesn't tell you that the arity 4 version also accepts (conn_or_endpoint, action, post_id, id) and not just (conn_or_endpoint, action, post_id, params).
I don't think there's any better auto generated documentation for the generated route functions right now in Phoenix. I usually just look at the output of mix phoenix.routes and pass in conn_or_endpoint followed by the action followed by every :var in the route, optionally followed by a params map.

phoenix view module not available

My application works and api json requests and for regular html. My router.ex
defmodule MyApp.Router do
use MyApp.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/api", MyApp do
pipe_through :api # Use the default browser stack
scope "/v1", V1, as: :v1 do
resources "/users", UserController, except: [:new, :edit, :index]
end
end
scope "/", MyApp do
pipe_through :browser # Use the default browser stack
get "/confirm/:token", UserController, :confirm, as: :user_confirm
end
end
my web/controllers/v1/user_controller.ex
defmodule MyApp.V1.UserController do
use MyApp.Web, :controller
def create(conn, %{"user" => user_params}) do
...
conn
|> put_status(:created)
|> put_resp_header("location", v1_user_path(conn, :show, user))
|> render("sign_up.json", user: Map.put(user, :session, result[:session]))
...
end
and my web/controllers/user_controller.rb
defmodule MyApp.UserController do
use MyApp.Web, :controller
alias MyApp.User
def confirm(conn, %{"token" => token}) do
...
render(conn, "confirmed.html")
...
end
end
my web/views/v1/user_view.ex
defmodule MyApp.V1.UserView do
use MyApp.Web, :view
...
end
and my web/views/user_view.ex
defmodule MyApp.UserView do
use MyApp.Web, :view
end
Everything works fine until I added a route and a controller for html.
Now, when I make a request for api json, I get an error
Request: POST /api/v1/users
** (exit) an exception was raised:
** (UndefinedFunctionError) function MyApp.V1.UserView.render/2 is undefined (module MyApp.V1.UserView is not available)
But if I delete web/vews/user_view.ex, then this query works without errors.
How can you correct this error?
These types of errors can usually be resolved by running mix clean. You may also see this type of error during Live code reload in dev. It case, try restarting the Phoenix.Server, and if that does not help, run mix clean

heroku: ActionController::RoutingError (No route matches [GET] "/newrelic")

ERROR
ActionController::RoutingError (No route matches [GET] "/newrelic")
# and I am getting error page for both staging and production heroku servers
Documentation
https://devcenter.heroku.com/articles/newrelic
GEM
https://github.com/newrelic/rpm
# ruby 2.1.0p0
# rails 4.0.1
Both environment variables NEW_RELIC_LICENSE_KEY and NEW_RELIC_APP_NAME are set to heroku config variable
Gemfile
gem "newrelic_rpm", "~> 3.5.7.59"
config/newrelic.yml
common: &default_settings
license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %>
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %>
monitor_mode: true
developer_mode: false
log_level: info
browser_monitoring:
auto_instrument: true
audit_log:
enabled: false
capture_params: false
transaction_tracer:
enabled: true
transaction_threshold: apdex_f
record_sql: obfuscated
stack_trace_threshold: 0.500
error_collector:
enabled: true
capture_source: true
ignore_errors: "ActionController::RoutingError,Sinatra::NotFound"
development:
<<: *default_settings
monitor_mode: true
developer_mode: true
test:
<<: *default_settings
monitor_mode: false
production:
<<: *default_settings
monitor_mode: true
staging:
<<: *default_settings
monitor_mode: true
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Staging)
[NOTE: I have two application hosted to heroku:]
(staging).herokuapp.com
(production).herokuapp.com
And I want to configure new-relic for both environments/servers.
Also, Note that this configuration is working fine in development(localhost) environmet.
EDITED
config/routes.rb
Demo::Application.routes.draw do
root :to => "home#index"
devise_for :users,:controllers => {:sessions => "sessions",:omniauth_callbacks => "omniauth_callbacks" }
post '/tinymce_assets' => 'tinymce_assets#create'
resources :home
namespace :admin do
resources :dashboards
resources :users do
member do
get :reset
put :reset_pw
put :delete_record
put :restore_user
end
end
end
resources :drives do
member do
put :destroy_drive
post :add_consolidation
put :delete_consolidation
post :add_driveorganizer
put :delete_drive_organizer
put :restore_drirve
end
collection do
get :recalculate_consolidation
end
resources :drive_details do
resources :images
end
end
resources :products do
member do
post :add_category
put :destroy_pc
put :delete_product
put :restore_products
end
end
resources :stores do
member do
put :delete_store
end
end
resources :store_products do
member do
put :delete_storeproduct
post :add_package_items
put :delete_package_item
put :restore_store_product
get :get_product_price
end
collection do
get :autocomplete_others
end
end
resources :orders do
member do
put :delete_order
put :restore_order
get :charge_stripe
end
resources :order_items do
collection do
post :display_price
end
member do
put :delete_record
end
end
end
resources :categories do
member do
put :delete_category
put :restore_category
end
collection do
get :move
end
end
namespace :user do
resources :campaigns do
member do
get :single_campaign
end
resources :stores
resources :carts do
collection do
post :carts_update
get :checkout_final
get :payment
post :payment
get :update_payment
get :update_payment_and_redirect
get :confirmation
post :confirmation
get :finish
post :confirmation_update
put :empty_cart
post :shelter_survey
end
member do
put :destroy_oi
put :checkout
end
end
end
end
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
end
Thanks
Based on the error you're getting, it looks like you're trying to access the route to the New Relic Ruby agent's developer mode in your staging and production environments. Developer mode installs a middleware in your app that responds to any URL prepended with /newrelic. Because you've enabled Developer mode in your development (localhost) environment (the developer_mode key is set to true in your newrelic.yml under development), accessing this route succeeds there, but it fails in staging and production because you don't have developer mode enabled in those environments.
Your current configuration is usually desirable, since Developer mode introduces a large amount of overhead that is generally unacceptable in production. Rather than attempt to access the route in staging or production, use it during development only.
You may also want to consider upgrading the version of the agent you are using, since version 3.5.7 does not fully support Ruby 2.0 or Rails 4. More information on releases can be found at https://docs.newrelic.com/docs/releases/ruby.

Ruby Rails 3.2 Locale with folder_name path in URL

I have a trio of Ruby/Rails applets running under the following setup:
services.mydomain.com/applet1
services.mydomain.com/applet2
services.mydomain.com/applet3
These are served via Phusion Passenger, and App1 and App2 work exactly as expected.
The problem is with App3 which uses I18n Locales embedded in the URL:
services.mydomain.com/applet3/en/
services.mydomain.com/applet3/fr/
services.mydomain.com/applet3/es/
The problem seems to be that the link_to URLs don't seem to include the "applet3". So instead of:
services.mydomain.com/applet3/en/signin
I get:
services.mydomain.com/en/signin
... which is unrouteable.
My routes.rb looks like:
Rails.application.routes.draw do
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
resources :users
resources :sessions, only: [:new, :create, :destroy]
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
root to: "static_pages#home"
end # scope locale
end # Rails.application.routes.draw do
... and in app/controllers/application_controller.rb I have:
before_filter :set_locale_from_params
def url_options
{ only_path: true, locale: I18n.locale }
end
protected
def set_locale_from_params
if params[:locale]
if I18n.available_locales.include?(params[:locale].to_sym)
I18n.locale = params[:locale]
else
flash.now[:notice] = 'Translation not available'
logger.error flash.now[:notice]
end
end
end
... and in config/environments/production.rb I have:
Rails.application.routes.default_url_options[:host] = 'http://services.mydomain.com/applet3/'
EDIT1: add example link_to statement
<%= link_to(t(".#{language}"), root_path(locale: language)) %>
/EDIT1
If I move App3 to a more "normal" arrangement where there is no "folder_name" in the URL path, everything works fine. So it's something simple I'm missing with how to set up the scope or the URL Options.
Thanks in advance for any help & suggestions!
what about use constraints into your route to define your sub module route ?
Rails.application.routes.draw do
constraints(:host) do
scope :path => ":locale" , locale: /#{I18n.available_locales.join("|")}/ do
resources :users
resources :sessions, only: [:new, :create, :destroy]
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
root to: "static_pages#home"
end # scope locale
end # constraints
end # Rails.application.routes.draw do
You are using root_path and expecting applet3 to be added, on doing rake routes did you check what was the path for root ?
You might have to explicitly set the root path in your routes file to enable routes_path work properly.

Verb-agnostic matching in Sinatra

We can write
get '/foo' do
...
end
and
post '/foo' do
...
end
which is fine. But can I combine multiple HTTP verbs in one route?
This is possible via the multi-route extension that is part of sinatra-contrib:
require 'sinatra'
require "sinatra/multi_route"
route :get, :post, '/foo' do
# "GET" or "POST"
p request.env["REQUEST_METHOD"]
end
# Or for module-style applications
class MyApp < Sinatra::Base
register Sinatra::MultiRoute
route :get, :post, '/foo' do
# ...
end
end
However, note that you can do this simply yourself without the extension via:
foo = lambda do
# Your route here
end
get '/foo', &foo
post '/foo', &foo
Or more elegantly as a meta-method:
def self.get_or_post(url,&block)
get(url,&block)
post(url,&block)
end
get_or_post '/foo' do
# ...
end
You might also be interested in this discussion on the feature.
FWIW, I just do it manually, with no helper methods or extensions:
%i(get post).each do |method|
send method, '/foo' do
...
end
end
Although if you're doing it a lot it of course makes sense to abstract that out.
Phrogz has a great answer, but if either lambdas or including sinatra-contrib isn't for you, then this meta method will achieve the same result as sinatra-contrib for your purposes:
# Provides a way to handle multiple HTTP verbs with a single block
#
# #example
# route :get, :post, '/something' do
# # Handle your route here
# end
def self.route(*methods, path, &block)
methods.each do |method|
method.to_sym
self.send method, path, &block
end
end
If you're a little wary of being able to send arbitrary methods to self, then you can protect yourself by setting up a whitelist of allowed methods in an array, and then checking for the symbol's presence in the array.
# Provides a way to handle multiple HTTP verbs with a single block
#
# #example
# route :get, :post, '/something' do
# # Handle your route here
# end
def self.route(*methods, path, &block)
allowed_methods = [:get, :post, :delete, :patch, :put, :head, :options]
methods.each do |method|
method.to_sym
self.send(method, path, &block) if allowed_methods.include? method
end
end
Here's a service-unavailable server that I managed to get on single line :)
require 'sinatra';set port: ARGV[0]||80;%w.get post put patch options delete..map{|v|send(v,'*'){503}}
I actually used this to test the behavior of some client code in the face of 503s.

Resources