Mount an engine on subdomain Rails 3.1 - ruby-on-rails-3

I am doing some experiments with Mountable Engines. First i need your opinion for a scenario, Is it a good idea that we make "chunk of large modules" in an application as "mountable engines".
I tried this it works great, In mountable engine we can access models of app globally and in app we can access engine models with module prefix. So it works great for me.
Now came to original question:
I want to mount an engine to a subdomain, so that every request with specific subdomain should be served by that specific engine. I used this code.
root :to=>'dashboard#index'
scope :subdomain => 'admin' do
mount MyAdmin::Engine => '/'
end
In this case mydomain.com and admin.mydomain.com goes to dashboard controller. If i change the preferences like that
scope :subdomain => 'admin' do
mount MyAdmin::Engine => '/'
end
root :to=>'dashboard#index'
In this case mydomain.com and admin.mydomain.com goes to engine specific root controller.
How can we accomplish this scenario and mount an engine on specific sub-domain?

I accomplish the task by using these route entries:
scope :subdomain => 'www' do
root :to=>'dashboard#index'
end
scope :subdomain => 'admin' do
mount MyAdmin::Engine => '/'
end

Working with Rails 3.2.12 and ruby 1.9.3-194 I came to a different solution that also works locally for avoiding the www. subdomain issue while allowing there to be an Engine at a certain subdomain.
get "home/index"
constraints :subdomain => 'store' do
mount Spree::Core::Engine, :at => '/'
end
root :to => 'home#index'
I could totally be wrong but it's working so far.

Related

Subdomain routing with devise not working on heroku

I have defined a few types of users using devise (members, company_users, etc) and I'd like to use different subdomains for the login pages of each type of user.
I've referred to this railscast in order to implement the matching of the subdomain and redirect to the appropriate action. My routes.rb file looks like this:
devise_for :company_users, :controllers => { :registrations => 'company_users/registrations', :sessions => 'company_users/sessions' }
devise_scope :company_user do
constraints Subdomain do
match '/' => 'company_users/sessions#new'
end
end
And my lib/subdomain.rb file:
class Subdomain
def self.matches?(request)
request.subdomain.present? and request.subdomain =~ /\Acompanies\z/
end
end
Locally, it works perfectly. I've tested using companies.lvh.me:3000 (as the same railscast suggests) and it really redirects to the correct login page.
In order to try and make it work on Heroku I have added the domain, using heroku domains:add companies.mydomain.com, and I have added a new CNAME record on my DNS server, pointing to my Heroku application.
However, when I try to access companies.mydomain.com it redirects me to the root path, and not to the correct login page. I'm kind of clueless of what's happening. Any help will be appreciated.
This happen when the tld of your domain is different from tld of the heroku domain.
Mine is .com.br and I have to add config.action_dispatch.tld_length = 2 to production.rb, so Rails can parse the URL correctly and redirect to the right subdomain.

API subdomain for Heroku app, is it possible?

I am trying to build an API and I am concerned that all my resources will either not be accessible with the api.myapp.com domain or that they will "live" with the wrong uris.
I have added the CNAME for my domain name to point to my Heroku app.
(ex: browsing to www.myapp.com takes you to https://myherokuapp.heroku.com)
I would like to set up an API subdomain, so that a GET to
https://api.myapp.com takes you to https://myherokuapp.heroku.com/api/v1
The best scenario would be that a POST to https://api.myapp.com/accounts/12345 would create a new account. Is that even possible?
(I know that subdomains (eg: mysubdomain.myappname.heroku.com) are not possible with Heroku)
I believe the answer could be in three different places:
Something to do with DNS provider forwarding configs (maybe
something to do with "A" records).
Something to config in Heroku, possibly a paid add-on to handle domains/subdomains.
Handle all subdomains within my app.
If you want to differentiate between api.mydomain.com and www.mydomain.com and have different controllers for your API requests then you could certainly use Rails routes constrained to your api subdomain to handle this
constraints :subdomain => "api" do
scope :module => "api", :as => "api" do
resources :posts
end
end
which would then use the posts_controller.rb in the app/controllers/api folder of your application.
You'll then have both www.mydomain.com and api.mydomain.com added a custom domains for your application and then the routes will take care of the rest.
You might also want to look into the Grape Gem for helping build your api

Rails "automatic" routes don't work, must specify with get "controller/method" every time?

I did
rails generate controller home index
But it adds this line to my routes.rb
get "home/index"
I thought Rails could deduce controller/method from the URL automatically? Why do I need to specify every get/post page?
Here's my complete routes.rb file:
Callisto2::Application.routes.draw do
root :to => "home#index"
resources :assets
end
root "/" works fine. so does /assets/*.
What's the problem with /home/index? I get the error:
Routing Error
No route matches [GET] "/home/index"
Try running rake routes for more information on available routes.
rake routes (run as apache user) gives me the following output:
root / home#index
Thanks for any clarifications. Not sure what I'm missing.
Edit: I didn't make this clear: I manually removed get /home/index from routes.rb to keep that file clean.
Rails used to add the so called catch all route at the bottom of your routes file:
match ':controller(/:action(/:id(.:format)))'
There was nothing 'automatic' or magical about these urls, just that every rails app started out with this route in their routes.rb
This has fallen out of favour, at least partially because it makes everything accessible over get, whereas
resources :books
Adds each route with the appropriate http verb. Listing routes explicitly is also a lot less verbose than when rails started out.
If your controller is home and the action is index your path is just /home.
You can find more information here.

Subdomain constraints and url helpers on a domain with a subdomain (sub-subdomain?)

So I have read all about how to use Rails 3 subdomain constraints and url helpers, which works great for most applications. For instance, if I want an admin subdomain (which I do) I can use:
constraint :subdomain => :admin
scope :module => :admin
defaults :subdomain => 'admin'
But my application runs on many (customers') domains, and usually on a subdomain of it. So, something like directory.customer.com. Now if I apply that logic to admin.directory.customer.com, Rails things directory is part of the subdomain, so I have to do this:
constraint :subdomain => /^admin.*/
scope :module => :admin
defaults :subdomain => 'admin'
This is great, just match any subdomain that stats with admin, BUT when it comes to using the url helpers, it's NOT great, because the default subdomain I've set (admin) doesn't include the customer's portion of the subdomain (directory).
Setting the :host option to directory.customer.com doesn't seem to fix this, the url helper still returns admin.customer.com. Is there any way to set it up so url helpers "know" that the directory.customer.com is all part of the :host and the subdomain shouldn't overwrite that part of the host name? There's got to be a method I can modify or something to make it keep that host name intact, right?

rails 3 sessions across subdomains not working in Internet Explorer

I am working on a rails 3 application which use subdomains. I used railscasts #221 "Subdomains in rails 3" (http://railscasts.com/episodes/221-subdomains-in-rails-3) as a guide and everything goes well, except in Explorer.
To keep my session across all the subdomains I put the next line in session_store.rb as the tutorial says:
MyApp.application.config.session_store :cookie_store, :key => '_myapp_session', :domain => "example.com"
I have tested my app on Firefox and Chrome and it works well, but for some reason is not working at all in Internet Explorer. The behavior is strange because sometimes it seems the session is share across all my subdomains, but some others there are some subdomains where I am logged in and other sudomains where I am not logged in.
I can't find any reason for this and I would appreciate any idea...
I am using Devise for authentication with rails 3.0.5
I believe you'll need to change your domain value to .example.com (the leading dot indicates that the cookie can be used across subdomains):
MyApp.application.config.session_store :cookie_store, :key => '_myapp_session', :domain => ".example.com"
For some reason this did not work (rails 3.2.11) for any session data that was set on a subdomain. It took a piece of custom Middleware to fix it. A summary of that solution is below.
tl;dr: You need to write a custom Rack Middleware. You need add it into your conifg/environments/[production|development].rb. This is on Rails 3.2.11
Cookie sessions are usually stored only for your top level domain.
If you look in Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com} You can see that there will be separate entries for sub1.yourdomain.com and othersub.yourdomain.com and yourdomain.com
The challenge is to use the same session store file across all subdomains.
Step 1: Add Custom Middleware Class
This is where Rack Middleware comes in. Some relevant rack & rails resources:
Railscasts about Rack
Railsguide for Rack
Rack documentation for sesssions abstractly and for cookie sessions
Here is a custom class that you should add in the lib
This was written by #Nader and you all should thank him
# Custom Domain Cookie
#
# Set the cookie domain to the custom domain if it's present
class CustomDomainCookie
def initialize(app, default_domain)
#app = app
#default_domain = default_domain
end
def call(env)
host = env["HTTP_HOST"].split(':').first
env["rack.session.options"][:domain] = custom_domain?(host) ? ".#{host}" : "#{#default_domain}"
#app.call(env)
end
def custom_domain?(host)
host !~ /#{#default_domain.sub(/^\./, '')}/i
end
end
Basically what this does is that it will map all of your cookie session data back onto the exact same cookie file that is equal to your root domain.
Step 2: Add To Rails Config
Now that you have a custom class in lib, make sure are autoloading it. If that meant nothing to you, look here: Rails 3 autoload
The first thing is to make sure that you are system-wide using a cookie store. In config/application.rb we tell Rails to use a cookie store.
# We use a cookie_store for session data
config.session_store :cookie_store,
:key => '_yourappsession',
:domain => :all
The reason this is here is mentioned here is because of the :domain => :all line. There are other people that have suggested to specify :domain => ".yourdomain.com" instead of :domain => :all. For some reason this did not work for me and I needed the custom Middleware class as described above.
Then in your config/environments/production.rb add:
config.middleware.use "CustomDomainCookie", ".yourdomain.com"
Note that the preceding dot is necessary. See "sub-domain cookies, sent in a parent domain request?" for why.
Then in your config/environments/development.rb add:
config.middleware.use "CustomDomainCookie", ".lvh.me"
The lvh.me trick maps onto localhost. It's awesome. See this Railscast about subdomains and this note for more info.
Hopefully that should do it. I honestly am not entirely sure why the process is this convoluted, as I feel cross subdomain sites are common. If anyone has any further insights into the reasons behind each of these steps, please enlighten us in the comments.