I'm using Rails 5 and Nginx, if that's relevant
I'd like to create a website where a user can be assigned a custom subdomain. Unfortunately, I have no idea how I'd implement that.
Would the best way be using Rails routing? Or should this be an Nginx thing?
Any help is appreciated!
Check https://stackoverflow.com/a/29483146/4515647
Basically:
Validate that the property that will be used as a subdomain (e.g. 'name') is not something like 'www'
Get models (e.g. User) from request.subdomain in controller
Create a Subdomain class like the following that is autoloaded:
:
Class Subdomain
def self.matches?(request)
case request.subdomain
when 'www', '', nil
false
else
true
end
end
end
Configure your routes
Related
In Rails route, usually we do constraints: {domain: "example.com" } if we want to specify specific routes that example.com can have. But how do I reverse this such that everyone can access this except example.com
You can create custom constraint. Add more excluded domains if you want.
class DomainConstraint
def matches?(request)
excluded_hosts = ['example.com']
excluded_hosts.exclude?(request.host)
end
end
Use it like this:
constraints DomainConstraint.new do
..
end
https://guides.rubyonrails.org/routing.html#advanced-constraints
I'm using the apartment gem in a rails app.
I have one database with schemas for each tenant and one public schema for the Tenant table.
I have excluded the www subdomain:
Apartment::Elevators::Subdomain.excluded_subdomains = ['www']
Then, if I enter public.page.com or www.page.com, Apartment won't switch to another tenant, but it will stay at the public one. Of course "public" is not a tenant itself, is just the common data between tenants, so, I don't want any user using the public schema.
What would be the correct way to avoid this?
This app is running on AWS, so, route 53 is going to prevent this, but, although I want to avoid rails from serving request through this subdomain.
Apart from excluding domain from Apartment, you need to exclude them from routes.
In my project I'm using this code for manage this:
I'm using initializer to create array of excleded subdomains.
# config/initializers/apartment/subdomain_exlusions.rb
Apartment::Elevators::Subdomain.excluded_subdomains = ['www', 'admin']
Then, we can use this array in helper class in routes.
# config/routes.rb
class ExcludedSubdomainConstraint
def self.matches?(request)
request.subdomain.present? && !Apartment::Elevators::Subdomain.excluded_subdomains.include?(request.subdomain)
end
end
Rails.application.routes.draw do
constraints ExcludedSubdomainConstraint do
# here routes that are accessible in subdomains
end
end
As a bonus, you can route excluded subdomains to another constrain
class DashboardSubdomainConstraint
def self.matches?(request)
Apartment::Elevators::Subdomain.excluded_subdomains.include?(request.subdomain) || request.subdomain == ''
end
end
constraints DashboardSubdomainConstraint do
namespace :dashboard do
get '/settings'
end
end
will give you a route like www.domain.com/dashboard/settinigs with access to public tenant.
TIP. And you can use different root method in concerns
I'm currently trying to setup masking for one of my rails app subdomains.
Hypothetically, my main app website is called www.cats.com
I've got a subdomain on this main application called www.care.cats.com
I've got another domain managed by GoDaddy called www.catscare.com
Currently, I have it setup such that going to www.catscare.com goes to www.care.cats.com as it should. However, whenever I try to add a slug at the end of that link for example (www.catscare.com/blah), my rails application gives me a 404, whereas if I go to www.care.cats.com/blah, it gives me the correct page. I think this has something to do with my subdomain constraints in my routes.rb file.
scope "/:slug", module: :claims_portal, as: :claims_portal, constraints: ClaimsPortalConstraint.new do
My actual constraints file is here:
class ClaimsPortalConstraint
def matches?(request)
in_claims_subdomain?(request) && merchant_exists?(request)
end
private
def in_claims_subdomain?(request)
request.subdomain =~ /^(claims|claims-sandbox|claims-staging|claims-regression|care|care-sandbox|care-staging|care-regression)$/
end
def merchant_exists?(request)
Company.find_by(slug: request.params[:slug]).present?
end
end
I am pretty new to Rails and most of my knowledge depends on tutorials :)
So, I followed this http://www.railstutorial.org tutorial and created really good site but now I run into a problem. For my users I have a special column in my database which shows which type of user he is. For example I have column 'student' which is 'true' if user is student and 'false' if he's not.
Now I would like to create a subdomain for students. So, when student wants to sign up or sign in he would be transferred to www.student.mysite.com instead of www.mysite.com.
How can I accomplish that?
Thank you :)
There are a number of ways to do this, specifically you'll be interested in looking up multi-tenancy in respect to rails
--
Multi Tenancy
Whilst multi tenancy is typically the definition of having multiple databases / assets (one for each user), however, as it's ridiculously difficult to get this working in rails (something we're currently working on), you can use the principle with a single stack of data
There are several tutorials on how to achieve this with Rails here:
Basecamp-style subdomains by DHH (although looks like the post is down)
Multitenancy with PostgreSQL (Railscasts)
Apartment Gem (achieving multi tenancy on Rails)
Although this is not directly related to your question, most of the "multi tenancy" questions
are typically based on "how do I create different subdomains for my users"
--
Subdomains
The basis of subdomains on Rails is to capture the request, and route it to the correct controller. We've managed to achieve that using the following setup:
#config/routes.rb
constraints Subdomain do #-> lib/subdomain.rb & http://railscasts.com/episodes/221-subdomains-in-rails-3
#Account
namespace :accounts, path: "" do #=> http://[account].domain.com/....
#Index
root to: "application#show"
end
end
#lib/subdomain.rb
class Subdomain
def self.matches?(request)
request.subdomain.present? && request.subdomain != 'www'
end
end
This will give you the ability to do the following:
#app/controllers/accounts/application_controller.rb
class Account::ApplicationController < ActionController::Base
before_action :set_account
def show
##account set before_action. If not found, raises "not found" exception ;)
end
private
#Params from Subdomain
def set_account
params[:id] ||= request.subdomains.first unless request.subdomains.blank?
#account = Account.find params[:id]
end
end
Ideally, we'd love to handle this in the middleware, but as it stands, this is what we've got!
This will give you the ability to call the data you need from the #account variable:
#app/views/accounts/application/show.html.erb
<%= #account.name %>
I am a new Rails Developer
My application_controller is:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :sshow
def sshow
puts "==========================="
puts YAML::dump(request.subdomains)
end
end
now when I put kausik.localhost:3000 in my browser address bar it
returns blank Array [] instead ['kausik'] .
Also I rewrite etc/host file for this subdomain.
As #injekt said in the comments, you can't work with subdomains using localhost. The simplest alternative is to use the lvh.me domain which points all subdomains to 127.0.0.1. To do this, simply start your rails server and go to kausik.lvh.me:3000.
Also, if you simply need the first subdomain, you can use request.subdomain, which in this case would return "kausik".
There's a very nice RailsCast about subdomains in Rails.