📜 ⬆️ ⬇️

Rails Subdomains

I think everyone who worked with sub-domains in Rails 3 saw this screencast .

When faced with this example, the task was to make dynamic subdomains + some fixed ones. Dynamic had to correspond to some field of one of the models. Thus the conditions for the final solution were put forward:

Implementation


For the implementation of the first item, the above example was taken as the basis and expanded with the possibility of transferring one’s own subdomain or their array.
subdomain / base.rb
module Subdomain class Base attr_accessor :subdomain def initialize(param = ["www"] ) @subdomains = case param.class.to_s when "String", "Symbol" [param] when "Array" param else [] end end def matches?(request) self.subdomain?( request ) && ( @subdomains.map {|i| i.to_s == request.subdomain }.include? true ) end protected def subdomain?(request) request.subdomain.present? and ( request.subdomain != "www" ) end end end 

I think nothing to explain here.
Next came the turn for the implementation of the second paragraph.
In this class, in the method of checking the coincidence, an instance of the class is obtained by its name. Further, we check the presence of a subdomain in the table.
subdomain / active_record.rb
 class Subdomain::ActiveRecord < Subdomain::Base attr_reader :model attr_accessor :field def initialize(params) p = params.first @model = p[1] @field = p[0] end def matches?(request) obj = case @model.class when String @model.classify.constantize when Symbol @model.to_s.classify.constantize else @model end subdomain?(request) and ( obj.superclass == ActiveRecord::Base ) and obj.where(field.to_sym => request.subdomain).first.present? end end 

And the third step was to simplify the recording of rules in routes.rb . If you use the option that offers an example, you get quite cumbersome records and not quite clear at first glance.
 constraints( Subdomain::ActiveRecord.new Site::User, :login ) do root :to => "main#index" end constraints( Subdomain::Base.new [:admin] ) do scope :module => "admin", :as => :admin do root :to => "main#index" end end 

To add your method you need to extend the class responsible for the path, namely ActionDispatch :: Routing :: Mapper
For this, a module was written that was added to the main class during the application loading process.
config / initializers / subdomain.rb
 ActionDispatch::Routing::Mapper.send(:include, Subdomain::Extension) 

subdomain / extension.rb
 module Subdomain module Extension def subdomain( sub, params = {} ) if params[:scope] scope :module => params[:scope].to_s, :as => params[:scope].to_sym do unscoped_subdomain( sub ) { yield } end else m = case sub.class.to_s when "Symbol", "String" sub.to_s when "Array" sub.first when "Hash" nil end if m.blank? or params.key?(:scope) unscoped_subdomain( sub ) { yield } else scope :module => m, :as => m.to_sym do unscoped_subdomain( sub ) { yield } end end end end def unscoped_subdomain( sub ) case sub.class.to_s when "Symbol", "String", "Array" constraints( Subdomain::Base.new sub ) { yield } when "Hash" p = sub.first inst = "subdomain/#{p[0].to_s}".classify.constantize constraints( inst.new p[1] ) { yield } end end end end 


Then the previously mentioned structures were replaced by the following:
 subdomain( :active_record => { :login => Site::user } ) do root :to => "main#index" end subdomain( :admin ) do root :to => "main#index" end # subdomain( :base => :admin ) do root :to => "main#index" end 

Result


The result was a fairly user-friendly interface for working with subdomains.
 subdomain( "subdomain" ) do root :to => "main#index"# controller => subdomain/main path => subdomain_root end subdomain( "subdomain", :scope => "probe" ) do root :to => "main#index"# controller => probe/main path => probe_root end subdomain( "subdomain", :scope => false ) do root :to => "main#index"# controller => main end subdomain( ["subdomain1", "subdomain2"], :scope => "test" ) do root :to => "main#index" # controller => test/main end subdomain( ["subdomain1", "subdomain2"] , :scope => false ) do root :to => "main#index" # controller => main end subdomain(:_ =>  ) do root :to => "main#index"# controller => main end # ActiveRecord subdomain( :active_record => { :_ =>  } ) do root :to => "main#index"# controller => main end subdomain( :active_record => { :_ =>  }, :scope => "models" ) do root :to => "main#index"# controller => models/main end 

Constructive criticism and advice are welcome. I apologize in advance for the places crooked code.
')
PS : files are available in the archive .
PPS : regarding syntax highlighting, everything is in the preview, for some reason it is not in the final version.

Source: https://habr.com/ru/post/129688/


All Articles