Rails route for api on subdomain - api

I want to make the API of my Rails app accessible through a subdomain (https://api.domain.com). I have the following routes defined:
constraints :subdomain => 'api' do
namespace :api, defaults: {format: 'json'} do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :posts
end
end
end
This works but results in the following url:
https://api.domain.com/api/posts
I would like it to be:
https://api.domain.com/posts
The API controllers are in app/controllers/api/v1 where they should stay.
I tried mapping the route but without any success. Does somebody know how to fix this?

Change
namespace :api, defaults: {format: 'json'} do
to
namespace :api, path: nil, defaults: {format: 'json'} do

Related

No route matches [GET] "/products"

i follow this How To but i have No route matches error...
i have this routes.rb:
# config/routes.rb
require 'api_constraints'
Rails.application.routes.draw do
namespace :api, defaults: { format: :json }, constraints: { subdomain: 'api' }, path: '/' do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :products, only: [:index, :show, :create, :destroy]
end
end
end
Rake Routes:
api_products GET /products(.:format) api/v1/products#index {:format=>:json, :subdomain=>"api"}
POST /products(.:format) api/v1/products#create {:format=>:json, :subdomain=>"api"}
api_product GET /products/:id(.:format) api/v1/products#show {:format=>:json, :subdomain=>"api"}
DELETE /products/:id(.:format) api/v1/products#destroy {:format=>:json, :subdomain=>"api"}
This is the error:
ActionController::RoutingError (No route matches [GET] "/products")
I presume that the request is getting rejected at subdomain constraint. I think you make request to http://localhost:3000/produtcts, but you need some url like http://api.****/products. There is a guide how to do it locally http://shapeshed.com/developing-subdomain-rails-sites-locally/

creating a custom path-helper while using FreindlyID

we're trying to get our site to have less scrapeable AND more readable urls
so e.g.
www.loomio.org/discussions/3122
becomes
www.loomio.org/d/3saA4ds9/lets-go-to-the-moon
we only really want the human-readable slug on show-links, so www.loomio.org/d/3saA4ds9/edit should be the url for editing that discussion
the solution so far follows the top answer here:
Ruby on Rails: How to override the 'show' route of a resource?
modify routes.rb:
get '/d/:id/:slug', to: 'discussions#show', as: :discussion
resources :discussions, path: 'd', except: [:edit, :show] do
get :activity_counts, on: :collection
member do
post :update_description
post :add_comment
post :show_description_history
get :new_proposal
post :edit_title
put :move
end
end
install gem FriendlyID; make and populated a :key column on Discussion table; add the following to discussion.rb (model):
KEY_LENGTH = 10
extend FriendlyId
friendly_id :key
write a custom path helper for group_path. in groups_helper.rb:
def group_url(group, options={})
url_for(options.merge(:controller => 'groups', :action => 'show',
:id => group.key, :slug => group.full_name.parameterize))
end
def group_path(group, options={})
group_url(group, options.merge(:only_path => true))
end
rake routes produces:
group GET /g/:id/:slug(.:format) groups#show
and while calling group_path(group) seems to work in some cases, I'm also seeing strange unrelated urls get generated, like :
http://loomio.org/group_requests/TegFOIx4DB/start_new_group?action=show&controller=groups%2Fgroups&slug=19-tory
in console, I'm also getting errors such as:
[5] pry(main)> g = Group.last
[6] pry(main)> app.group_path(g)
ActionController::RoutingError: No route matches {:controller=>"groups", :action=>"show", :id=>#<Group id: 2811, name: "Sylvester Buckridge", created_at: "2013-12-10 06:25:42", updated_at: "2013-12-10 06:25:42", privacy: "public", members_invitable_by: "members", parent_id: nil, email_new_motion: true, hide_members: false, beta_features: false, description: "A description for this group", memberships_count: 1, archived_at: nil, max_size: 300, cannot_contribute: false, distribution_metric: nil, sectors: nil, other_sector: nil, discussions_count: 0, motions_count: 0, country_name: nil, setup_completed_at: "2013-12-10 05:25:01", next_steps_completed: false, full_name: "Sylvester Buckridge", payment_plan: "undetermined", viewable_by_parent_members: false, key: "rkdlTytOin">}
from /home/s01us/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.16/lib/action_dispatch/routing/route_set.rb:540:in `raise_routing_error'
I've tried putting the group_path and grop_url methods in ApplicationController and ApplicationHelper to no avail.
calling
group_path( group.key, group.fullname.parameterize )
works, but would ideally like to be able to only have to call e.g.
group_path(#group)
as far as i understand the problem, you could use the good old hack with defining the to_param method on your model
class Group < ActiveRecord::Base
def to_param
"#{id}-#{slug}"
end
end
The beauty of this solution is that you won't need to do anything else. Rails will automatically use the to_param method as your record ID when it generates an URL from a record. You can do anything
redirect_to group_path(#group)
redirect_to #grup
# etc
and your Group.find should eat it as it is 123-smth-smth, usually it is smart enough to extract the integer part of the id

My login route doesn't work after trying to force SSL via routes.rb

I want people to be able to both subscribe and login to my application via SSL. My original route, which was not SSL, was this:
resource :login, controller: "sessions" do
collection do
get 'new'
get 'create'
end
end
Worked great, but was unencrypted. Then I tried this:
scope :protocol => 'https://', :constraints => { :protocol => 'https://' } do
resource :login, controller: "sessions" do
collection do
get 'new'
get 'create'
end
end
end
Now Rails me:
No route matches [GET] "/login"
when I navigate to https://myapp.dev/login
Please note I am using Pow in development mode.
hmm, I was thinking it would just be
scope :constraints => { :protocol => "https" } do
resource :login, controller: "sessions" do
collection do
get 'new'
get 'create'
end
end
end
and you could put more resource entries under there as needed
Why don't you leave the route as is and add in your production.rb file:
config.force_ssl = true
This way you will have all the traffic routed via SSL, not only the login controller, which is a good practise to protect your user session cookies.

How to set root_url

In my Ruby on Rails 3.1 app I have a link like this:
<%= link_to 'Home', root_url %>
On My dev. machine it renders a link with "localhost:3000". On production it renders a link with an IP Address like this "83.112.12.27:8080". I would like to force rails to render the domain address instead of the IP Address. How can I set root_url?
You are looking for ActionController's default url option. So you can do something like:
class ApplicationController < ActionController::Base
def default_url_options
if Rails.env.production?
{:host => "www.example.com"}
else
{}
end
end
end
This also works for ActionMailer. As well, both can be set in your environment .rb or application.rb
# default host for mailer
config.action_mailer.default_url_options = {
host: 'example.com', protocol: 'https://'
}
# default host for controllers
config.action_controller.default_url_options = {
:host => "www.example.com"
}
In your routes set:
root :to => 'welcome#index'
and in your links set:
<%=link_to "Home", root_path %>
It will render
Home
So in your localhost It'd take you to
http://localhost:3000/
and in your production server It'd take you to
http://yourdomian.com/
and the routes.rb will render the index action of the controller welcome by default.
PS. you also need to remove index.html from public directory in order to use this.
UPDATE
A little bit more on routing:
Rails Routing from the Outside In
Perhaps you could just do something like this in your ApplicationController:
class ApplicationController < ActionController::Base
helper_method :home_uri
def home_uri
Rails.env.production? ? 'http://www.yourdomain.com' : root_url
end
...
end
And then change your link to be like this: <%= link_to 'Home', home_uri %>
This makes a helper method, home_uri, which returns the url you desired if the application is being run in the development environment. I don't think that you can easily overwrite root_url, and I also think it's likely a bad idea. I had the helper method end with uri instead of url because rails uses the router to automatically create methods that end with url, so if you had a route named home, this solution won't overwrite or conflict with that named route helper method. You can read more about named route helper methods here if you're interested.

Rails 3 I18n routes

I have such routes in my app:
# config/routes.rb
Demo::Application.routes.draw do
root :to => "requests#index"
match 'find' => 'requests#find'
get "about/developer"
get "about/api"
end
All works ok.
But I want to enable I18n urls and changed routes: (by the official Rails guide):
# config/routes.rb
Demo::Application.routes.draw do
scope "(:locale)" do
root :to => "requests#index"
get "about/developer"
get "about/api"
match 'find' => 'requests#find'
end
end
After adding scope lines it gives error:
Exiting
C:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/gems/actionpack-3.0.3/lib/action_dispatch/routing/mapper.rb:160:in
`default_controller_and_action':
missing :controller (ArgumentError)
What's up? Official guide is wrong?
My Rails version: 3.0.3, Ruby 1.8.7
Does it work if you specify all of the controller/action names?
In other words, try changing:
get "about/developer"
get "about/api"
to:
get "about/developer" => "about#developer"
get "about/api" => "about#api"