<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>tangramor (唐图)</title>
    <link>https://ruby-china.org/tangramor</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>自己写了个 shell 脚本来替换 Capistrano，放 github 上了</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/tangramor/deploy_rails" rel="nofollow" target="_blank"&gt;https://github.com/tangramor/deploy_rails&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;参考了很多人的部署经验，例如&lt;a href="http://ruby-china.org/topics/12033" title=""&gt;蝉游记网站的部署 Nginx,Unicorn,Capistrano,OOB,Graceful Restart&lt;/a&gt;。因为对 Capistrano 的配置和部署方式颇感不爽，就自己用 bash 脚本实现了自动对集群的部署。&lt;/p&gt;

&lt;p&gt;写了个使用指南，还没中文版……&lt;/p&gt;
&lt;h2 id="deploy_rails"&gt;deploy_rails&lt;/h2&gt;
&lt;p&gt;Use Shell script to update rails applications on remote servers through git, and execute bundle install, rake db:migration, asset precompile and restart unicorn...&lt;/p&gt;

&lt;p&gt;I tried to use Capistrano to do the deployment, but met a lot of problems, such as configuration error, ruby version not match, code upgrade caused runtime error...then I decided to write my own script to do the job.&lt;/p&gt;
&lt;h2 id="Prerequirements"&gt;Prerequirements&lt;/h2&gt;
&lt;p&gt;You may need to follow steps below to deploy you ruby on rails application to a Ubuntu + Nginx + Unicorn environment. Here I installed RVM as multiple users mode. And I use &lt;code&gt;www-data&lt;/code&gt; user to run my app (which is the user for Apache and Nginx on Ubuntu). &lt;/p&gt;

&lt;p&gt;You can also refer to other tutorials to do the initial deployment, such as &lt;a href="http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn/" rel="nofollow" target="_blank" title=""&gt;Lighting fast, zero-downtime deployments with git, capistrano, nginx and Unicorn&lt;/a&gt;, but it uses Capistrano, so if you follow it completely, you don't need my tool... &lt;/p&gt;

&lt;p&gt;Or you can refer to &lt;a href="https://www.digitalocean.com/community/articles/how-to-deploy-rails-apps-using-unicorn-and-nginx-on-centos-6-5" rel="nofollow" target="_blank" title=""&gt;How To Deploy Rails Apps Using Unicorn And Nginx on CentOS 6.5&lt;/a&gt; if you are using CentOS. But if you are using different OS, you may need adjust some configurations in following steps accordingly.&lt;/p&gt;
&lt;h3 id="0. Deploy source code to "&gt;0. Deploy source code to "production" servers&lt;/h3&gt;
&lt;p&gt;As root, change user &lt;code&gt;www-data&lt;/code&gt;'s shell to bash and set its home folder to &lt;code&gt;/var/www&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="# vi /etc/passwd"&gt;# vi /etc/passwd&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;www-data:x:33:33:www-data:/var/www:/bin/sh
==&amp;gt;
www-data:x:33:33:www-data:/var/www:/bin/bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To checkout source code from git server, you need to create ssh key for &lt;code&gt;www-data&lt;/code&gt; and add the public key string to your git server (github or private gitlab)&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su - www-data
$ ssh-keygen ###(Here don't input any password)
$ cat /var/www/.ssh/id_rsa.pub
......
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On your production server, check out your application code from git server.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su - www-data
$ git clone https://github.com/MYNAME/MYAPP.git

&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="1. Change configuration of the application for "&gt;1. Change configuration of the application for "production" environment:&lt;/h3&gt;&lt;h4 id="config/database.yml"&gt;config/database.yml&lt;/h4&gt;
&lt;p&gt;Here I use MySql, you may change to your database type accordingly&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;production:
adapter: mysql2
encoding: utf8
reconnect: false
database: MyApp
pool: 5
username: root
password: password
socket: /var/run/mysqld/mysqld.sock
host: 192.168.1.61
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="config/environments/production.rb"&gt;config/environments/production.rb&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Disable Rails’s static asset server (Apache or nginx will already do this)
config.serve_static_assets = true
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="2. Setup RVM for multi-users"&gt;2. Setup RVM for multi-users&lt;/h3&gt;
&lt;p&gt;I use this mode because I want user &lt;code&gt;www-data&lt;/code&gt; can use rvm directly &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ \curl -L https://get.rvm.io | sudo bash -s stable
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="3. Setup Ruby by RVM"&gt;3. Setup Ruby by RVM&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rvmsudo rvm get head
$ rvmsudo -s rvm pkg install openssl
$ sudo su -

###(The following changes only for China mainland, because it is very slow to connect https://rubygems.org/)

# gem sources –remove https://rubygems.org/

# gem sources -a http://ruby.taobao.org/

# gem sources -l

*** CURRENT SOURCES ***
http://ruby.taobao.org
### ensure only ruby.taobao.org

# sed -i ‘s!ftp.ruby-lang.org/pub/ruby!ruby.taobao.org/mirrors/ruby!’$rvm_path/config/db

# exit

$ rvmsudo -s rvm install 2.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open &lt;code&gt;/etc/bash.bashrc&lt;/code&gt; or &lt;code&gt;/etc/bashrc&lt;/code&gt; (whichever is available) and add the following to the end of the file. Also run this command in your terminal.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PATH=$PATH:/usr/local/rvm/gems/ruby-2.0.0-p247/bin
export RAILS_ENV=production
source /etc/profile.d/rvm.sh
rvm use 2.0.0 &amp;gt;/dev/null 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open /var/www/.bashrc and add following:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source /etc/profile.d/rvm.sh
rvm use 2.0.0 &amp;gt;/dev/null 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="4. Setup Unicorn as root"&gt;4. Setup Unicorn as root&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo su -
# gem install bundler
# gem install unicorn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or &lt;code&gt;gem install –verbose –debug unicorn&lt;/code&gt; (with detailed information)&lt;/p&gt;

&lt;p&gt;if got exception like:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception `OpenSSL::SSL::SSLError’ at /usr/local/rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/openssl/buffering.rb:174 – read would block
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Edit .gemrc :    &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;–-
:ssl_verify_mode: 0
:backtrace: false
:benchmark: false
:bulk_threshold: 1000
:sources:
- http://ruby.taobao.org/
:update_sources: true
:verbose: true
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="5. Setup some required libs (for my app):"&gt;5. Setup some required libs (for my app):&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# apt-get install libmysqlclient-dev imagemagick libmagickwand-dev
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="6. Install bundlers as root"&gt;6. Install bundlers as root&lt;/h3&gt;
&lt;p&gt;First, add following to Gemfile of the application:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem 'unicorn'
gem 'unicorn-worker-killer'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then execute following commands:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# bundle update rails
# bundle install
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="7. Configure Unicorn to be executed by www-data"&gt;7. Configure Unicorn to be executed by www-data&lt;/h3&gt;&lt;h4 id="$ vi config/unicorn.rb"&gt;$ vi config/unicorn.rb&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# config/unicorn.rb
# Set environment to development unless something else is specified
env = ENV["RAILS_ENV"] || "development"

# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
worker_processes 6

app_root = File.expand_path("../..", __FILE__)
working_directory app_root

# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen "/tmp/unicorn.socket", :backlog =&amp;gt; 64
listen 4096, :tcp_nopush =&amp;gt; false

# Preload our app for more speed
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
  GC.copy_on_write_friendly = true

# nuke workers after 300 seconds instead of 60 seconds (the default)
timeout 300

pid "#{app_root}/tmp/pids/unicorn.pid"

# Production specific settings
if env == "production"
  # Help ensure your application will always spawn in the symlinked
  # "current" directory that Capistrano sets up.
  working_directory app_root

  # feel free to point this anywhere accessible on the filesystem
  user 'www-data', 'www-data'

  stderr_path "#{app_root}/log/unicorn.stderr.log"
  stdout_path "#{app_root}/log/unicorn.stdout.log"
end

# Force the bundler gemfile environment variable to
# reference the Сapistrano "current" symlink
before_exec do |_|
  ENV["BUNDLE_GEMFILE"] = File.join(app_root, 'Gemfile')
end

before_fork do |server, worker|
  # the following is highly recomended for Rails + "preload_app true"
  # as there's no need for the master process to hold a connection
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end

  # Before forking, kill the master process that belongs to the .oldbin PID.
  # This enables 0 downtime deploys.
  old_pid = app_root + '/tmp/pids/unicorn.pid.oldbin'
  if File.exists?(old_pid) &amp;amp;&amp;amp; server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

after_fork do |server, worker|
  # Disable GC, together with the OOB after to reduce the execution time
  GC.disable
  # the following is *required* for Rails + "preload_app true",
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end

  # if preload_app is true, then you may also want to check and
  # restart any other shared sockets/descriptors such as Memcached,
  # and Redis.  TokyoCabinet file handles are safe to reuse
  # between any number of forked children (assuming your kernel
  # correctly implements pread()/pwrite() system calls)
end

&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="$ vi config.ru"&gt;$ vi config.ru&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This file is used by Rack-based servers to start the application.

require ‘unicorn/oob_gc’
require ‘unicorn/worker_killer’

# execute 1 GC every 10 requests
use Unicorn::OobGC, 10

# Set the max request time to avoid mem leak by GC (random from 3072 to 4096 so the processes will not kill themselves at the same time)
use Unicorn::WorkerKiller::MaxRequests, 3072, 4096

# Set the max memery size to avoid mem leak by GC (random from 192 to 256 MB so the processes will not kill themselves at the same time)
use Unicorn::WorkerKiller::Oom, (192*(1024**2)), (256*(1024**2))

require ::File.expand_path(‘../config/environment’,??__FILE__)
run MyApp::Application
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="8. Configure Nginx"&gt;8. Configure Nginx&lt;/h3&gt;&lt;h4 id="# vi /etc/nginx/sites-enabled/default"&gt;# vi /etc/nginx/sites-enabled/default&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upstream myapp {
    # fail_timeout=0 means we always retry an upstream even if it failed
    # to return a good HTTP response (in case the Unicorn master nukes a
    # single worker for timing out).
    # for UNIX domain socket setups:
    server unix:/tmp/unicorn.socket fail_timeout=0;
}

server {
    listen   80; ## listen for ipv4; this line is default and implied
    #listen   [::]:80 default_server ipv6only=on; ## listen for ipv6

    root /var/www/MYAPP/public;
    index index.html index.htm;

    # Make site accessible
    server_name myhostname.com;

    location / {
        proxy_pass  http://myapp;
        proxy_redirect     off;

        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

        client_max_body_size       10m;
        client_body_buffer_size    128k;

        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;

        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;

    }

    location ~ ^/(assets)/{
        root /var/www/MYAPP/public;
        expires max;
        add_header Cache-Control public;
    }

    location ~* \.(jpg|jpeg|gif|png|ico|css|bmp|js|html)$ {
        root   /var/www/MYAPP/public;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Deploy the script"&gt;Deploy the script&lt;/h2&gt;&lt;h3 id="1. Copy unicorn scritp to /etc/init.d/unicorn and make it executable"&gt;1. Copy &lt;a href="https://github.com/tangramor/deploy_rails/blob/master/unicorn" rel="nofollow" target="_blank" title=""&gt;unicorn&lt;/a&gt; scritp to &lt;code&gt;/etc/init.d/unicorn&lt;/code&gt; and make it executable&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x /etc/init.d/unicorn
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="2. Edit /etc/init.d/unicorn to match your environment"&gt;2. Edit &lt;code&gt;/etc/init.d/unicorn&lt;/code&gt; to match your environment&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USER="www-data"
DAEMON=unicorn
RUBY_VERSION=2.0.0
RAILS_ENV=production
RVM_PROFILE="/etc/profile.d/rvm.sh"
APPPATH="/var/www/MYAPP"
DAEMON_OPTS="-c $APPPATH/config/unicorn.rb -E $RAILS_ENV -D"
NAME=unicorn
DESC="Unicorn app for $USER"
PID=$APPPATH/tmp/pids/unicorn.pid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In most cases, you just need to modify &lt;code&gt;USER&lt;/code&gt;, &lt;code&gt;RUBY_VERSION&lt;/code&gt;, &lt;code&gt;RAILS_ENV&lt;/code&gt;, &lt;code&gt;RVM_PROFILE&lt;/code&gt; and &lt;code&gt;APPPATH&lt;/code&gt; to the values of your server&lt;/p&gt;
&lt;h3 id="3. Set unicorn auto start when boot up"&gt;3. Set unicorn auto start when boot up&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# update-rc.d unicorn defaults
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="4. Configure SSH connection between workstation and servers"&gt;4. Configure SSH connection between workstation and servers&lt;/h3&gt;
&lt;p&gt;You need to generate ssh key on your workstation. For example, my work machine is a laptop and I installed Ubuntu 13.10 on it, so I generate ssh key by execute &lt;code&gt;ssh-keygen&lt;/code&gt; without input passphrase for the key (this will generate a key with no passphrase)&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/USERNAME/.ssh/id_rsa):
......
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then append the public key string to the servers. In this case we use &lt;code&gt;www-data&lt;/code&gt; user, so just log in the server, open &lt;code&gt;/var/www/.ssh/authorized_keys&lt;/code&gt; and add the content of &lt;code&gt;/home/USERNAME/.ssh/id_rsa.pub&lt;/code&gt; on you workstation to it:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;On your workstation------------------------------------------
$ scp ~/.ssh/id_rsa.pub ServerUser@192.168.1.61:~/id_rsa.pub
$ ssh ServerUser@192.168.1.61

Now we are on 192.168.1.61-----------------------------------
$ cat ~/id_rsa.pub | sudo -u www-data sh -c "cat - &amp;gt;&amp;gt;/var/www/.ssh/authorized_keys"
$ rm ~/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="5. Deploy code changes"&gt;5. Deploy code changes&lt;/h3&gt;
&lt;p&gt;After you committed any change on you app and pushed to your git server, you can execute &lt;a href="https://github.com/tangramor/deploy_rails/blob/master/update_unicorn.sh" rel="nofollow" target="_blank" title=""&gt;update_unicorn.sh&lt;/a&gt; to deploy the changes to your production servers. You need to edit &lt;code&gt;update_unicorn.sh&lt;/code&gt; to match your environment.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SERVER_IPS=(192.168.1.61 192.168.1.62)
SERVER_USERS=(www-data www-data)
RUBY_VERSION=2.0.0
RVM_PROFILE="/etc/profile.d/rvm.sh"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example we have 2 servers: 192.168.1.61 and 192.168.1.62, they are 2 nodes of a cluster. You can reduce or add servers here. And on both servers we use &lt;code&gt;www-data&lt;/code&gt; user to execute the rails application.&lt;/p&gt;
&lt;h3 id="Reference:"&gt;Reference:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://ihower.tw/rails3/deployment.html" rel="nofollow" target="_blank"&gt;http://ihower.tw/rails3/deployment.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://ruby-china.org/topics/12033" rel="nofollow" target="_blank"&gt;http://ruby-china.org/topics/12033&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://ruby.taobao.org/" rel="nofollow" target="_blank"&gt;http://ruby.taobao.org/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn/" rel="nofollow" target="_blank"&gt;http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>tangramor</author>
      <pubDate>Fri, 28 Feb 2014 09:36:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/17554</link>
      <guid>https://ruby-china.org/topics/17554</guid>
    </item>
    <item>
      <title>如何向 Ruby on Rails 分页插件 will_paginate 的链接插入其它参数 </title>
      <description>&lt;p&gt;（适用 3.0 版 will_paginate）&lt;/p&gt;

&lt;p&gt;WillPaginate 是 RoR 里很方便的一个分页用的 gem，例如在控制器里面写&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在视图里面写&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= will_paginate @posts %&amp;gt;  
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以自动给 Post 对象分页显示了。&lt;/p&gt;

&lt;p&gt;不过如果你想给一个通过搜索表单返回的搜索结果进行分页，使用 will_paginate 就不那么方便了，因为它不会在它的链接里自动附上搜索参数，这样除非你的模型里面明确定义了搜索方法（参考 &lt;a href="https://github.com/mislav/will_paginate/wiki/Simple-search" rel="nofollow" target="_blank"&gt;https://github.com/mislav/will_paginate/wiki/Simple-search&lt;/a&gt; ），否则对一些复杂的搜索条件（例如你需要组合一些搜索条件）就无能为力了。&lt;/p&gt;

&lt;p&gt;当然 will_paginate 考虑到了大家的需求，所以你可以通过覆盖它的 WillPaginate::ActionView::LinkRenderer 类里的方法来给它的分页链接添加额外参数。&lt;/p&gt;

&lt;p&gt;（这里给出的方式参考了国外网友对 3.0 以下 will_paginate 的 hack）&lt;/p&gt;

&lt;p&gt;首先，在 app/helpers 下创建文件 remote_link_renderer.rb：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# This class intends to add extra URL request parameters in pagination links  &lt;/span&gt;
&lt;span class="c1"&gt;# Usage:  &lt;/span&gt;
&lt;span class="c1"&gt;#   &amp;lt;%  &lt;/span&gt;
&lt;span class="c1"&gt;#    search_params = {:search =&amp;gt; @search,  &lt;/span&gt;
&lt;span class="c1"&gt;#                    :page_num =&amp;gt; @page,  &lt;/span&gt;
&lt;span class="c1"&gt;#                    :serial =&amp;gt; @serial,  &lt;/span&gt;
&lt;span class="c1"&gt;#                    :code =&amp;gt; @code,  &lt;/span&gt;
&lt;span class="c1"&gt;#                    :rule =&amp;gt; @rule  &lt;/span&gt;
&lt;span class="c1"&gt;#                    }  &lt;/span&gt;
&lt;span class="c1"&gt;#   %&amp;gt;   &lt;/span&gt;
&lt;span class="c1"&gt;#   &amp;lt;%= will_paginate @codes, :renderer =&amp;gt;'RemoteLinkRenderer', :remote =&amp;gt; search_params %&amp;gt;  &lt;/span&gt;
&lt;span class="c1"&gt;#  &lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RemoteLinkRenderer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;WillPaginate&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ActionView&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;LinkRenderer&lt;/span&gt;  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="vi"&gt;@remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:remote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;  
    &lt;span class="k"&gt;super&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;  

  &lt;span class="kp"&gt;private&lt;/span&gt;  

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;  
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt; &lt;span class="no"&gt;Fixnum&lt;/span&gt;  
        &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:rel&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rel_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
      &lt;span class="k"&gt;end&lt;/span&gt;  

      &lt;span class="c1"&gt;# here to compose key-value pairs to one string like "&amp;amp;key1=value1&amp;amp;key2=value2"  &lt;/span&gt;
      &lt;span class="n"&gt;string_remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@remote.inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;  
        &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;  
          &lt;span class="n"&gt;attrs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sx"&gt;%(&amp;amp;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;CGI&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;escapeHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;)&lt;/span&gt;  
        &lt;span class="k"&gt;end&lt;/span&gt;  
        &lt;span class="n"&gt;attrs&lt;/span&gt;  
      &lt;span class="k"&gt;end&lt;/span&gt;  

      &lt;span class="c1"&gt;# append the extra parameters to target  &lt;/span&gt;
      &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;string_remote&lt;/span&gt;  
      &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;end&lt;/span&gt;  

&lt;span class="k"&gt;end&lt;/span&gt;  

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，在视图文件里，根据你自己的搜索表单修改 search_params 内容&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%  &lt;/span&gt;
  &lt;span class="n"&gt;search_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:search&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                  &lt;span class="ss"&gt;:rule&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                  &lt;span class="ss"&gt;:registered&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@registered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                  &lt;span class="ss"&gt;:reservation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@reservation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                  &lt;span class="ss"&gt;:reg_uid&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@reg_uid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="sx"&gt;%&amp;gt;  

&amp;lt;%= will_paginate @posts, :renderer =&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'RemoteLinkRenderer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:remote&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;search_params&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;  

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意这里特地指定了 :renderer =&amp;gt;'RemoteLinkRenderer' 。这样你的分页链接里面都会附上你在 search_params 里面设定的参数，你就可以在控制器里面对这些参数进行处理了。&lt;/p&gt;</description>
      <author>tangramor</author>
      <pubDate>Mon, 28 Oct 2013 18:38:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/15098</link>
      <guid>https://ruby-china.org/topics/15098</guid>
    </item>
    <item>
      <title>ActiveRecord 的 qurey 里，哈希形式的参数如何实现 LIKE 检索？</title>
      <description>&lt;p&gt;&lt;a href="http://guides.rubyonrails.org/v3.2.13/active_record_querying.html" rel="nofollow" target="_blank"&gt;http://guides.rubyonrails.org/v3.2.13/active_record_querying.html&lt;/a&gt; 看了下，貌似不支持 LIKE？&lt;/p&gt;

&lt;p&gt;如何在支持 LIKE 检索的情况下避免 SQL 注入攻击？&lt;/p&gt;</description>
      <author>tangramor</author>
      <pubDate>Mon, 28 Oct 2013 18:35:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/15097</link>
      <guid>https://ruby-china.org/topics/15097</guid>
    </item>
    <item>
      <title>同时使用 bootstrap-sass，bootstrap-rails</title>
      <description>&lt;p&gt;我的环境是多用户环境（multiuser）RVM + Ruby 2.0.0 p247 + Rails 3.2.14，用了 &lt;a href="https://github.com/RailsApps/rails3-bootstrap-devise-cancan" rel="nofollow" target="_blank"&gt;https://github.com/RailsApps/rails3-bootstrap-devise-cancan&lt;/a&gt; 做模板来构建基础系统。这个模板使用的是 bootstrap-sass&lt;/p&gt;

&lt;p&gt;在开发环境里面一切都很好，问题出在 assets:precompile，编译后的 js 不起作用，也就是说，bootstrap-dropdown, bootstrap-tab 这些在 production 环境下都不好使了。Google 了很多解决方案，试过都不好用。&lt;/p&gt;

&lt;p&gt;然后我就想替换一下 bootstrap 实现试试，于是把 bootstrap-sass 换成了 anjlab-bootstrap-rails，assets 里面的 application.js 和 bootstrap_and_overrides.css.scss 都做了相应改动：
application.js 是 &lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//= require bootstrap &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改成 &lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//= require twitter/bootstrap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;bootstrap_and_overrides.css.scss 是 &lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"bootstrap"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改成 &lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"twitter/bootstrap"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后注释掉了 &lt;a href="/import" class="user-mention" title="@import"&gt;&lt;i&gt;@&lt;/i&gt;import&lt;/a&gt; "bootstrap-responsive"; 因为 bootstrap-rails 里面没有这个&lt;/p&gt;

&lt;p&gt;重新 bundle install 和 rake assets:precompile 后，启动 rails s -e production，发现 bootstrap-dropdown、bootstrap-tab 这样的 js 功能都可用了，但是原来的 bootstrap css 不对了，标题栏从横向变成了标准的 ul 列表从上到下显示，把页面内容都挡住了。检查了 bootstrap-rails 的 css，发现它的实现不是标准的 bootstrap css，在它的 navbar 样式表定义里（ &lt;a href="https://github.com/anjlab/bootstrap-rails/blob/master/app/assets/stylesheets/twitter/bootstrap/_navbar.scss" rel="nofollow" target="_blank"&gt;https://github.com/anjlab/bootstrap-rails/blob/master/app/assets/stylesheets/twitter/bootstrap/_navbar.scss&lt;/a&gt; ）没有 .navbar-inner 这样的类定义。&lt;/p&gt;

&lt;p&gt;再次尝试过几种 stackoverflow 上的方案都不行，我决定不使用 bootstrap-rails 的样式表（删掉 bootstrap_and_overrides.css.scss 里面的&lt;a href="/import" class="user-mention" title="@import"&gt;&lt;i&gt;@&lt;/i&gt;import&lt;/a&gt; "twitter/bootstrap";），把 bootstrap-sass 的样式表定义（~/.rvm/gems/ruby-2.0.0-p247/gems/bootstrap-sass-2.3.2.2/vendor/assets/stylesheets/bootstrap/*）给拷贝到了 app/assets/stylesheets/bootstrap_sass 目录下，删除了 bootstrap.scss 和  responsive.scss，给除 _variables.scss 和 _mixins.scss 之外的每个文件顶部加上了&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"_variables"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"_mixins"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重新 bundle install 和 rake assets:precompile（它会自动包含 app/assets/stylesheets/bootstrap_sass 目录内容）后，启动 rails s -e production，一切 OK！&lt;/p&gt;</description>
      <author>tangramor</author>
      <pubDate>Tue, 03 Sep 2013 18:36:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/13864</link>
      <guid>https://ruby-china.org/topics/13864</guid>
    </item>
  </channel>
</rss>
