应用场景:比如guides.ruby-china.org就是使用subdomain的形式,其中guides是subdomain,ruby-china.org是domain.

基础知识:

1、不能使用开发环境测试subdomain

#不能使用开发环境的url作为测试subdomain,原因如下
req = ActionDispatch::Request.new 'HTTP_HOST' => 'http://www.example.com:8080'
req.subdomain #=>www
req.domain #=> example.com

req = ActionDispatch::Request.new 'HTTP_HOST' => 'http://www.localhost:8080'
req.subdomain #=>""
req.domain #=> www.localhost

2、安装和使用puma-dev

#删除pow
curl get.pow.cx/uninstall.sh | sh

#/usr/local/bin中添加两个文件
/usr/local/bin/pumad
#!/bin/bash
if [ ! -f Gemfile ]; then
  echo "Are you sure you're in a Ruby on Rails app?"
else
  ln -s "$(pwd)" ~/.puma-dev/"$(basename `pwd`)"
  puma-dev -install
  echo "Your app should be available at http://$(basename `pwd`).dev and https://$(basename `pwd`).dev now!"
fi

#/usr/local/bin/unpumad
rm ~/.puma-dev/"$(basename `pwd`)"

#改变文件的权限
chmod +x /usr/local/bin/pumad
chmod +x /usr/local/bin/unpumad

#安装语句
brew install puma/puma/puma-dev
sudo puma-dev -setup
puma-dev -install

#停止所有puma-dev上的app
pkill -USR1 puma-dev

3、constraints

#parameter constraints
constraints(id: /\d+\.\d+/) do
  resources :posts
end

resources :posts do
  constraints(post_id: /\d+\.\d+/) do
    resources :comments
  end
end

#ip constraints
constraints(ip: /192\.168\.\d+\.\d+/) do
  resources :posts
end

#request constraints, block对象方式
constraints(-> (req) { req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do
  resources :iphones
end

#request constraints,定义类方式
#config/initializers/iphone.rb
#定义的类必须存在matches?类方法,参数就是request,如果定义是的matches?实例方式,下面的routes.rb中为constraints(Iphone.new)
class Iphone
  def self.matches?(request)
    request.env["HTTP_USER_AGENT"] =~ /iPhone/
  end
end
#config/routes.rb
constraints(Iphone) do
  resources :iphones
end

4、实例

#实例blog has many posts
#rails g scaffold blog name subdomain
#rails g scaffold post title content:text blog:references
#rails g controller welcome index

#添加gem和seed
gem 'faker'
#seed.rb
10.times do
  company_name = Faker::Company.name
  blog = Blog.create(name: "#{company_name}'s Blog", subdomain: company_name)
  10.times do 
    blog.posts.create(
        title: Faker::Company.catch_phrase,
        content: Faker::Lorem.paragraphs(10, true).join("<br><br>")
      )
  end
end

#config/initializers/subdomain_routes.rb
class SubdomainRoutes
  def self.matches? request
    case request.subdomain
    when '', 'www'
      true
    else
      false
    end
  end
end
#routes.rb
Rails.application.routes.draw do
  constraints(SubdomainRoutes) do
    resources :blogs, only: [:new]
    root 'welcome#index'
  end

  constraints(!SubdomainRoutes) do
    resources :blogs, except: [:index, :new] do
      resources :posts
    end
    root 'blogs#show'
  end
end

#model/blog.rb
class Blog < ApplicationRecord
  validates :subdomain, 
            exclusion: { in: %w(www), 
            message: "%{value} is reserved." }, 
            presence: true, 
            uniqueness: true
  before_validation :sanitize_subdomain

  has_many :posts

  private

  def sanitize_subdomain
    self.subdomain = self.subdomain.parameterize
  end
end

#application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  before_action :ensure_subdomain

  def current_blog
    @current_blog ||= Blog.find_by(subdomain: request.subdomain)
  end
  helper_method :current_blog

  private

  def ensure_subdomain
    redirect_to root_url(subdomain: :www) unless current_blog.present?
  end
end

#blogs_controller.rb
class BlogsController < ApplicationController
  before_action :set_blog, only: [:show, :edit, :update, :destroy]
  skip_before_action :ensure_subdomain, only: [:new, :create]

  def show
  end

  def new
    @blog = Blog.new
  end

  def edit
  end

  def create
    @blog = Blog.new(blog_params)
    if @blog.save
      redirect_to root_path, notice: 'Blog was successfully created.'
    else
      render :new
    end
  end

  def update
    if @blog.update(blog_params)
      redirect_to root_path, notice: 'Blog was successfully updated.'
    else
      render :edit
    end
  end

  def destroy
    @blog.destroy
    redirect_to root_url(subdomain: nil), notice: 'Blog was successfully destroyed.'
  end

  private

    def set_blog
      @blog = current_blog
    end

    def blog_params
      params.require(:blog).permit(:name, :subdomain)
    end
end

#welcome_controller.rb
class WelcomeController < ApplicationController
  skip_before_action :ensure_subdomain

  def index
    @blogs = Blog.all
  end
end

#blogs/show.html.erb
<%= link_to 'Blog Home', root_path, class: 'btn btn-info' %>
<%= link_to 'Site Home', root_url(subdomain: nil), class: 'btn btn-info' %>

#welcome/index.html.erb
<%= link_to "#{blog.subdomain}.example.dev", root_url(subdomain: blog.subdomain) %>

results matching ""

    No results matching ""