应用场景:比如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) %>