使用through关联时访问关系的属性

| 评论

0.有下面三个 model 关联,使用 through 来简化对 Ownership 的访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class User < ActiveRecord::Base
  # association
  has_many :ownerships, dependent: :destroy
  has_many :shops, through: :ownerships
end

class Ownership < ActiveRecord::Base
  belongs_to :user
  belongs_to :shop
end

class Shop < ActiveRecord::Base
  # association
  has_one  :ownership, dependent: :destroy
  has_one  :user, through: :ownership
end

1.此时无法在Shop中在 after_create 来访问 ownership 的 user_id 属性,因为这时 owership 还未创建。当事务 commit 以后 owership 被创建,同时拥有 user_id 属性。这时就可以获得 user_id 从而进行相关操作

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
class Shop < ActiveRecord::Base
  after_commit :get_attr_after_destroy, on: [:destroy]
  after_commit :get_attr_after_create,  on: [:create]

  after_create :get_attr_in_after_create

  # association
  has_one  :ownership, dependent: :destroy
  has_one  :user, through: :ownership

  private
    def get_attr_after_destroy
      user_id = self.ownership.user_id
    end

    def get_attr_after_create
      user_id = self.ownership.user_id
    end

    def get_attr_in_after_create
      # self.ownership is nil
      # NoMethodError: undefined method `user_id' for nil:NilClass
      user_id = self.ownership.user_id
    end
end

Rails 小提示

| 评论

  • 重写activerecord 的 method_missing 不是一个好的主意 #rails

在ubuntu上安装较新版本的nodejs

| 评论

1
2
3
4
5
sudo apt-get update
sudo apt-get install -y python-software-properties python g++ make
sudo add-apt-repository -y ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs

因为用到 add-apt-repository 可能需要安装 software-properties-common

1
sudo apt-get install software-properties-common

来源:Installing Node.js via package manager

在Ubuntu上使用nginx官方源安装nginx

| 评论

0.添加key

1
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ABF5BD827BD9BF62

1.添加到nginx官方源到 /etc/apt/sources.list

1
deb http://nginx.org/packages/ubuntu/ precise nginx

2.如果原来安装过nginx,备份相关配置文件后删除nginx及其相关组件

1
sudo apt-get purge nginx*

3.安装nginx

1
2
sudo apt-get update
sudo apt-get install nginx

4.安装成功后可以用-v查看ningx版本

1
2
nginx -v
#nginx version: nginx/1.4.4

来源:How to Setup Rails App With Puma and NGINX

修改git Push 后的commit Message

| 评论

背景:手快把一个有拼写错误的commit message给push了
如何:

1
2
git commit --amend #修改commit message
git push -f #强制提交,如果不强制提交会被拒绝

Ruby on Rails 中灵活的应用程序设置(一)

| 评论

本文介绍的方法以 ActiveRecord 为基础将应用程序的设置存储到数据库中
为了方便扩展,设置将以 json 的格式保存到数据库
同时设置是全局的,只需要一条数据记录就可以满足需求,于是用到了 singleton pattern
注意这种处理方法可能会有性能问题
下面进入正题
0.创建 AppSetting model

1
rails g model AppSetting

1.修改 AppSetting 的 migration

1
2
3
4
5
6
7
8
create_table :app_settings do |t|
  t.integer :singleton_guard
  t.text :value

  t.timestamps
end

add_index(:app_settings, :singleton_guard, :unique => true)

Ruby on Rails Rspec 测试的上传模拟

| 评论

Rspec 是一个 ruby 的测试框架,在进行 Ruby on Rails 开发时通常都会使用这个框架
本文不讨论如何在 Ruby on Rails 中 配置 Rspec
0.准备工作

0).在 Ruby on Rails 项目文件夹下的 spec/fixtures 下创建文件夹 files
1).把测试文件拷贝到该文件夹下面,这里的示例为 “egg.zip”, “egg.jpg”

1.引入 fixture_file_upload

1
include ActionDispatch::TestProcess

2.为测试准备上传文件

1
2
3
4
5
6
describe UploadController do
  before(:each) do
    @file = fixture_file_upload('/files/egg.zip', 'application/zip')
    @image = fixture_file_upload('/files/egg.jpg', 'image/jpeg')
  end
end

3.在测试中上传文件

1
2
3
4
5
6
7
8
9
10
11
12
13
describe "upload" do
  it "should upload file" do
    post :upload, :file => @file  #upload action is here
    expect(response).to redirect_to(upload_path)
    flash[:notice].include?("upload success").should equal(true)
  end

  it "should upload image" do
    post :upload, :file => @image  #upload action is here
    expect(response).to redirect_to(upload_path)
    flash[:notice].include?("upload success").should equal(true)
  end
end

4.运行测试

1
rspec spec/controllers/upload_controller_spec.rb

5.完整的 spec

upload_controller_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
require 'spec_helper'
include ActionDispatch::TestProcess

describe UploadController do
  before(:each) do
    @file = fixture_file_upload('/files/egg.zip', 'application/zip')
    @image = fixture_file_upload('/files/egg.jpg', 'image/jpeg')
  end

  describe "upload" do
    it "should upload file" do
      post :upload, :file => @file  #upload action is here
      expect(response).to redirect_to(upload_path)
      flash[:notice].include?("upload success").should equal(true)
    end

    it "should upload image" do
      post :upload, :file => @image  #upload action is here
      expect(response).to redirect_to(upload_path)
      flash[:notice].include?("upload success").should equal(true)
    end
  end
end