Posts match “ rails ” tag:

使用bullet来处理rails开发中的N + 1查询问题

github地址

在开发中,有时会碰到N + 1查询问题。

比如说,在Blog显示文章时, 文章的作者是由关联查询得出

#home_controller

@posts = Post.paginate :page => params[:page], :order => 'created_at DESC'

#views

@posts.each do |post|
..............
post.user.username
............

这样,每一篇文章都会有一个查询,怎么来改进代码呢?

首先,先安装bullet

group :development do
 gem 'bullet'
end

然后在config/environments/development.rb加入下面代码

  Bullet.enable = true
  Bullet.alert = true
  Bullet.bullet_logger = true
  Bullet.console = true
  Bullet.growl = false
  Bullet.rails_logger = true
  Bullet.disable_browser_cache = true

重启服务器

之后重新访问页面时就会弹出页面来提示你,当前页面有N+1问题,可以用:include => [:user]来解决

重新编辑home_controller

@posts = Post.paginate :page => params[:page], :order => 'created_at DESC', :include => [:user]

问题解决

使用Annotate为rails项目生成model的大纲

有时候在写代码时,想不起来当前model的字段属性了,annotate帮你忙。

annotate可以以注释的方式在你model文件的底部生成model的大纲(schema)信息

安装

gem install annotate

生成

cd /path/to/app/
annotate

便会生成下面的注释

# == Schema Information

#

# Table name: users

#

#  id                   :integer(4)      not null, primary key

#  email                :string(255)     default(""), not null

#  encrypted_password   :string(128)     default(""), not null

#  username             :string(255)     not null

#  reset_password_token :string(255)

#  remember_created_at  :datetime

#  sign_in_count        :integer(4)      default(0)

#  current_sign_in_at   :datetime

#  last_sign_in_at      :datetime

#  current_sign_in_ip   :string(255)

#  last_sign_in_ip      :string(255)

#  password_salt        :string(255)

Ubuntu下用apt-get安装rails环境

首先使用apt-get安装ruby

sudo apt-get install ruby

运行 ruby -v

ruby 1.8.7 (2010-06-23 patchlevel 299) [i686-linux]

ruby安装完毕

安装rubygems,注意,这里不要用apt-get来安装

先从官网下载最新版rubygems,并解压

cd /tmp;wget http://production.cf.rubygems.org/rubygems/rubygems-1.3.7.tgz

tar zxf rubygems-1.3.7.tgz

运行安装程序

sudo ruby setup.rb

会看到输出很多文字,最后一行是

RubyGems installed the following executables:

/usr/bin/gem1.8

然后做一个ln连接

sudo ln -s /usr/bin/gem1.8 /usr/bin/gem

输入gem -v 显示 1.3.7 说明 rubygems安装完毕,开始安装rails

sudo gem install rails

经过一段时间的等待和文字输出之后,运行 rails -v, 显示 Rails 3.0.3 说明安装正确

rails new newapp 开始享受rails的快乐吧!

rails趣谈'为什么rails在Array中有个forty_two方法'

有次,群里有人问,为什么在rails的Array中有个forty_two方法

先看代码

> irb
>> require 'activesupport'
=> true
>> a = Array.new(50).fill {|i| i+=1 }
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
>> a.forty_two
=> 42

经过网上一番探索,在这个网页得到了答案 网址

在rails2.2时代, 有些人扩展了Array方法,从Array#second写到了Array#tenth。

这太混乱了,于是DHH发话,只保留 second, third, fourth and fifth 但增加一个forty_two, 为什么呢?

因为这是 生命、宇宙以及任何事情的终极答案

生产环境下rake db:migrate报错database is not configured

我在服务器上运行了下面的命令

RAILS_ENV=production rake db:migrate

结果报错

> ** Invoke db:migrate (first_time)

> ** Invoke environment (first_time)

> ** Execute environment

> rake aborted!

> proudction database is not configured

google后得到解决方法,将RAILS_ENV参数放到最后

rake db:migrate RAILS_ENV=production

完美解决rails中国时区时间设置

解释4个时区设置的不同

  • config.active_record.default_timezone

  • config.time_zone

  • Time.zone

  • ENV['TZ']

分别解释如下:

  1. ENV['TZ']

这个变量指的是服务器系统变量,ubuntu下可以用cat /etc/timezone来查看

当这个值为 Asia/Shanghai时, 显示就是中国时间。

对于ruby/rails来说,这个值决定 Time.now的显示时间

  1. config.time_zone

这个值是rails系统对显示时间的默认设置,可以通过 rake time:zones:all 列出所有可以设置的时区

一般来说把这个设置为 'Beijing'

  1. Time.zone

这个是设置最终处理显示的时区,可以覆盖config.time_zone,参数和config.time_zone一样

可以参考 railscasts的这篇 Time Zones in Rails 2.1

  1. config.active_record.default_timezone

这里就是全文的关键了!

这个default_timezone是决定active_record对数据库交互的时区设置,也就是影响created_at和updated_at在数据库的记录时间。

只有两个参数:utc和:local, rails初始化时默认是utc,所以保存到数据库的时间是utc时间。

总结

要在界面和数据库都很好的显示处理中国时区时间,编辑/path/to/site/config/application.rb(rails2是environment.rb), 加入

config.active_record.default_timezone = :local
config.time_zone = 'Beijing'

完美解决rails中国时区时间设置

新建rails项目的参数设置

实例

rails new newapp -d=mysql -T -J

rails new newapp -d=postgresql -b=https://gist.github.com/611035

参数

rails new APP_PATH [options]

APP_PATH

/path/to/appname, 不管前面是多复杂的路径,最后的appname就是新建的项目的名称

rails new ~/Desktop/newapp  #在桌面目录上新建一个newapp目录,项目名叫newapp

options

-m, [--template=TEMPLATE]

用模板文件来创建项目,模板文件可以是本机文件,也可以是一个url地址

在使用模板文件创建项目时,可以按照模板文件的配置要求,生成对应的文件/目录

[--skip-gemfile]

不创建Gemfile文件

[--dev]

开发调试用,将项目的rails指向本地gem里的rails路径.

-d, [--database=DATABASE]

选择数据库,有mysql/oracle/postgresql/sqlite3/frontbase/ibm_db几种选择,默认是sqlite3

-O, [--skip-active-record]

不使用active-record

-J, [--skip-prototype]

不使用prototype

-T, [--skip-test-unit]

不使用prototype

-G, [--skip-git]

不创建.gitnore和.keeps

-b, [--builder=BUILDER]

用模板文件来创建项目,模板文件可以是本机文件,也可以是一个url地址

在使用模板文件创建项目时,可以按照模板文件的配置要求,生成对应的文件/目录

-r, [--ruby=PATH]

设置运行项目的ruby路径,默认是当前环境下的ruby路径

   [--edge]

从github更新最新的rails版本来运行项目

其他选项

Runtime options:

    -p, [--pretend]  # 运行脚本时不生成文件


    -q, [--quiet]    # 运行脚本时不输出信息

    -s, [--skip]     # 跳过已经存在的文件

    -f, [--force]    # 覆盖已经存在的文件


Rails options:
    -h, [--help]     # 显示帮助

    -v, [--version]  # 显示Rails版本号

rails中处理复数单词的pluralize方法

缘由

在日常开发中,有时候会碰到要将一些单词按照它的数量来按单复数显示

所幸rails已经考虑到了这一点,在ActionView中有一个方法

There are <%= pluralize @user.size, "user" %>.  

例子

    pluralize(1, 'person')
    # => 1 person


    pluralize(2, 'person')
    # => 2 people


    pluralize(3, 'person', 'users')
    # => 3 users


    pluralize(0, 'person')
    # => 0 people


深入研究pluralize方法:

def pluralize(count, singular, plural = nil)
  "#{count || 0} " + ((count == 1 || count =~ /^1(\.0+)?$/) ? singular : (plural || singular.pluralize))
end

可以看到英语单词的单复数是由String#pluralize方法提供,这个是由ActiveSupport::Inflector提供的一个扩展方法

在rails console里运行

"post".pluralize             # => "posts"

"octopus".pluralize          # => "octopi"

"sheep".pluralize            # => "sheep"

"words".pluralize            # => "words"

"CamelOctopus".pluralize     # => "CamelOctopi"  

继续研究ActiveSupport::Inflector.pluralize

def pluralize(word)
  result = word.to_s.dup

  if word.empty? || inflections.uncountables.include?(result.downcase)
    result
  else
    inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
    result
  end
end

可以看到单词的单复数的匹配设置是在inflection.pluarls里,那要如何修改呢?
rails已经有一个配置文件了,在/paht/to/site/config/initializers/inflections.rb

ActiveSupport::Inflector.inflections do |inflect|
  inflect.plural /^(ox)$/i, '\1en'
  inflect.singular /^(ox)en/i, '\1'
  inflect.irregular 'person', 'people'
  inflect.uncountable %w( fish sheep )
end  

plural和singual是匹配单复数的通用匹配规则,irregular是处理那些特殊单词变化,uncountbale就是那些单复数一样的单词

BDD for Rails

安装组件

安装 RSpec

添加到Gemfile

group :development, :test do
  gem 'rspec-rails', '~> 3.0'
end

然后

$ bundle install

初始化RSpec目录

$ rails generate rspec:install

创建RSpec的binstub

$ bundle binstubs rspec-core

安装 Fuubar

fuubar 是一个使用进度条来表示RSpec测试进度的工具。
添加到Gemfile

group :test do
  gem 'fuubar'
end

运行

$ bundle install

将其设置为RSpec默认输出格式,编辑.rspec

—format Fuubar
—color

安装 shoulda-matchers

shoulda-matchers为RSpec扩充了很多rails内置方法的测试功能,不用自己重复写那些复杂的内置测试。
添加到Gemfile

group :test do
  gem 'shoulda-matchers'
end

运行

$ bundle install

安装 Factory Girl

Factory Girl是一个生成测试对象的工具
添加到Gemfile

group :development, :test do
  gem 'factory_girl_rails'
end

运行

$ bundle install

在RSpec配置文件spec_helper.rb添加配置

RSpec.configure do |config|
  .
  .
  .
  # Factory Girl

  config.include FactoryGirl::Syntax::Methods

end

在application.rb里添加下列配置

#add these lines

class Application < Rails::Application
    config.generators do |g|
      g.stylesheets false
      g.javascripts false
      g.test_framework :rspec,
        :fixtures => true,
        :view_specs => false,
        :helper_specs => false,
        :routing_specs => false,
        :controller_specs => true,
        :request_specs => true
      g.fixture_replacement :factory_girl, :dir => spec/factories
    end 
end

安装 Faker

faker 是一个生成测试数据的的工具, 如生成邮箱地址,手机号码,姓名
添加到Gemfile

group :test do
  gem 'faker'
end

运行

$ bundle install

安装 Database Cleaner

database cleaner可以确保每一次测试时,测试数据库都是干净的,没有干扰数据。
添加到Gemfile

group :test do
  gem 'database_cleaner'
end

运行

$ bundle install

给RSpec添加配置文件spec/spec_helper.rb

$ .
  .
  .
  RSpec.configure do |config|
  .
  .
  .
    # Database Cleaner

    config.before(:suite) do
      DatabaseCleaner.strategy = :transaction
      DatabaseCleaner.clean_with(:truncation)
    end
    config.before(:each) do
      DatabaseCleaner.start
      FactoryGirl.lint            # if FactoryGirl is installed !!!

    end
    config.after(:each) do
      DatabaseCleaner.clean
    end
  end

安装 Capybara-webkit

添加到Gemfile

group :test do
    gem capybara-webkit
end

运行

$ bundle install

在spec/spec_helper.rb里添加配置

.
.
require 'capybara/rspec'
.
Capybara.javascript_driver = :webkit
.
RSpec.configure do |config|
.

安装 spring

添加到Gemfile

group :development, :test do
  gem 'spring'
  gem 'spring-commands-rspec'
end

运行

$ bundle install
$ spring binstub —all

安装 SimpleCov

添加到Gemfile

group :test do
  gem 'simplecov', require: false
end

运行

$ bundle install

spec_helper.rb 第一行加载 simplecov

require 'simplecov' # if using simple simplecov

# see https://github.com/colszowka/simplecov#filters for filter/grouping etc

SimpleCov.start do  # for example…

  add_filter '/spec/'
  add_filter '/features/'
  add_filter '/config/'
  add_group 'Controllers', 'app/controllers'
  add_group 'Models', 'app/models'
  add_group 'Helpers', 'app/helpers'
  # add_group 'Views', 'app/views' # only .rb files are included at present!

  add_group 'Libraries', 'lib'
end
# Previous content of helper now start here

确保.gitignore里过滤下列目录

# Simplecov results
/coverage

安装guard

添加到Gemfile

group :development, :test do
  gem 'guard'
  gem 'guard-bundler'
  gem 'guard-rails'
  gem 'guard-rspec'
  gem 'guard-puma' # to have Guard use the Puma server rather than WEBrick

end

初始化Guardfile

$ guard init

安装完成

demo地址

在rails4与postgresql中使用uuid作为主键

安装步骤

先确保已经安装了 ruby on rails 和 postgresql

rails new uuids —database postgresql
rails generate migration enable_uuid_ossp_extension
rails generate model document title:string author:string

打开postgresql的uuid-ossp插件

class EnableUuidOsspExtension < ActiveRecord::Migration
  def change
    enable_extension uuid-ossp
  end
end

设置migration

class CreateDocuments < ActiveRecord::Migration
  def change
   create_table :documents, id: :uuid, default: 'uuid_generate_v4()'  do |t|
      t.string :title
      t.string :author
      t.timestamps
    end
  end
end

运行migration

rake db:create
rake db:migrate

安装完成

在console里测试一下

rails c

irb(main):011:0> Document.create(title: “PostgreSQL UUID!”, author: “Fox ZoOL”)
=> #<Document id: “ec31b888-a491-49e7-afa9-ab59e9131d78”, title: “PostgreSQL rocks!”, author: “Fox ZoOL”, created_at: “2015-01-10 21:02:17”, updated_at: “2015-01-10 21:02:17”>

Tips

由于主键已经是uuid了, Document.firstDocument.last 的返回值会出错,需要重写一下scope

class Document < ActiveRecord::Base
  scope :first, -> { order(created_at).first }
  scope :last, -> { order(created_at DESC).first }
end