Skip to main content

6 posts tagged with "ruby on rails"

View All Tags

· 2 min read

記錄一下寫 bamboofox 平台的心得

其實當初這個平台是為了 migrate 以前的課程所建置的

當初的課程平台只能容納一個課程

所以主要的設計是要能容納多個課程為主

為了註冊方便就寫了 OAuth 登入

大部分的時間都是在 survey OAuth 是個怎麼樣的東西

還有網站要怎麼架起來之類的

比較麻煩的點是想要一個帳號能夠 link 多個 OAuth provider

像是原本用 facebook 註冊登入後

又想要 link 別的 social media (ex: github, google)

主要是參考這篇文章 https://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/

把和 OAuth 有關的欄位移出 User table 建立一個新的 table Identity

每個 user has_many identities

主要的邏輯是使用者登入可以 link 其他 OAuth

如果登入 OAuth 成功就新增 identity 給那個 user

下次登入的時候就會靠 identity 來找到同一個 user 了

主要架設平台的搭配是 nginx + passenger + rvm

migrate 的方式我是直接先架一個 phpmyadmin 起來

先新增新網站的 schema

然後慢慢把舊網站的資料改成新網站的形式

最後再直接 import 到新網站的資料庫

· 4 min read

簡單記錄一下 Ruby on Rails server setup 這裡用的是最新版的 Ubuntu 17.04 server 版 這篇會教你設定

  • nginx
  • passenger
  • Let's Encrypt(https)
  • postfix(mail server)

因為要設定 Let's Encrypt 和 postfix,所以要有一個 DNS 的 A Record 指向你的 ip 位置

Passenger

這裡主要有三種方法可以選

詳細內容可以參考這篇

  1. Standalone mode

只有 passenger

  1. Nginx integration mode

passenger 和 nginx 整合

  1. Apache integration mode

passenger 和 apache 整合

這裡選用的是第二種方法

因為 nginx 的效能比 apache 好

接著就開始安裝 nginx + passenger,大部分的步驟都跟這篇一樣

稍微要注意一下 ubuntu 的 code name,像是 17.04 的 code name 是 Zesty 在加 apt 的 repo 的時候要稍微改一下 code name

Install passenger packages

deb https://oss-binaries.phusionpassenger.com/apt/passenger xenial main => deb https://oss-binaries.phusionpassenger.com/apt/passenger zesty main

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
sudo apt-get install -y apt-transport-https ca-certificates

# Add our APT repository
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger zesty main > /etc/apt/sources.list.d/passenger.list'
sudo apt-get update

# Install Passenger + Nginx
sudo apt-get install -y nginx-extras passenger

Enable the passenger nginx module and restart nginx

修改 /etc/nginx/nginx.conf 檔案 將 # include /etc/nginx/passenger.conf 取消註解

重啟 nginx

sudo service nginx restart

Notice

另外網路上還有另一種裝 passenger 和 nginx 的方法

是自行下載下來編譯,所有的套件最後會放在 /opt 資料夾底下

我自己是不推薦這種方法,因為還要自己去設定 service script

Let's Encrypt

詳細可以參考這篇

Postfix

設定好 Let's Encrypt 後就會有 ssh key 了

Install postfix package

sudo apt install -y postfix

Configure postfix

修改 /etc/postfix/main.cf

原本應該是

# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key

修改成

# TLS parameters
smtpd_tls_cert_file=/etc/letsencrypt/live/bamboofox.nctucs.net/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/bamboofox.nctucs.net/privkey.pem
smtp_tls_security_level=may
smtpd_tls_security_level=may

我的 domain name 是 bamboofox.nctucs.net,這裡要修改成自己的 domain name

smtp_tls_security_level=maysmtpd_tls_security_level=may 是讓 email 寄信和收信加密

將自己的 ip 也加進 relay 的 list

修改 /etc/postfix/main.cf

mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128

修改成

mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 140.113.209.18 

這邊很重要因為之後用 devise 寄信的時候會有 certification 的問題

Restart postfix

sudo service postfix restart

Deploy ruby on rails project

參考這篇

直接從創 deploy 帳號開始做

Create deploy user

sudo adduser deploy
sudo adduser deploy sudo
su deploy

Install rvm

gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
\curl -sSL https://get.rvm.io | bash -s stable
echo "source ~/.rvm/scripts/rvm" >> .bashrc
source ~/.rvm/scripts/rvm
rvm install 2.4.0
rvm use 2.4.0 --default

Install basic gems

gem install bundler
gem install rails

Show passenger config

執行指令

passenger-config about ruby-command

會得到

passenger-config was invoked through the following Ruby interpreter:
Command: /home/deploy/.rvm/gems/ruby-2.4.0/wrappers/ruby
Version: ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux]
To use in Apache: PassengerRuby /home/deploy/.rvm/gems/ruby-2.4.0/wrappers/ruby
To use in Nginx : passenger_ruby /home/deploy/.rvm/gems/ruby-2.4.0/wrappers/ruby
To use with Standalone: /home/deploy/.rvm/gems/ruby-2.4.0/wrappers/ruby /usr/bin/passenger start

這要用在等下的 nginx config

Install nvm

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
nvm install stable

Install yarn

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn

Create basic app

rails new myapp --webpack=react

Deploy on nginx

修改 myapp 裡的 config/secrets.yml

這裡 secret 可以使用 rake secret 產生

production:
secret_key_base: d7913c3e87fadd4312ee1c5c1b13320caeecc72548f20b9122e2a1bf9ccdf0e9ecb86675168e578b5b3e960a81daa967c0081f69b082eb0c0e5df4b5810d71a9

修改 /etc/nginx/sites-available/default

server {

# SSL configuration
#
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/ssl-bamboofox.nctucs.net.conf;
include snippets/ssl-params.conf;

# Add these three lines

passenger_enabled on;
server_name bamboofox.nctucs.net;
root /home/deploy/myapp/public;
}

重啟 nginx

sudo service nginx restart

· 2 min read

Rails best practices 是一個可以幫你檢查 Rails 專案架構的 gem

比如說你在 route 裡面增加了一些 routing path 但是你的 controller 沒有相對應的 action 的話

它就會幫你檢查出來,並且顯示警告訊息

Installation

Add following line to Gemfile.rb

gem 'rails_best_practices', require: false
gem 'rails_best_practices-rake_task', require: false

rails_best_practices 是本身檢查架構的 gem rails_best_practices-rake_task 是方便寫 rake task 的 gem

Customize

要是想要 custom 一些 config

可以打指令產生 config

rails_best_practices -g

會產生 /config/rails_best_practices.yml

config 大概長得像這樣

#MoveModelLogicIntoModelCheck: { use_count: 4 }
NeedlessDeepNestingCheck: { nested_count: 2 }
NotRescueExceptionCheck: { }
NotUseDefaultRouteCheck: { }
NotUseTimeAgoInWordsCheck: { }
#OveruseRouteCustomizationsCheck: { customize_count: 3 }
ProtectMassAssignmentCheck: { }
RemoveEmptyHelpersCheck: { }
#RemoveTabCheck: { }

不想要檢查的 rule 可以直接註解掉即可

Rake task

如果要整合 travis ci 在每次 code push 的時候檢查架構的話,就要把 rails_best_practices 寫成 rake task,然後寫成 rake default 會跑的 task

lib/tasks/rails_best_practices.rake 加上這幾行

require 'rails_best_practices/rake_task'

RailsBestPractices::RakeTask.new

然後修改一下 Rakefile

require_relative 'config/application'

Rails.application.load_tasks
task default: [:rails_best_practices]

這樣當你打 rake 的時候就會自動幫你檢查架構了

References

· 2 min read

Rubocop 是一個 Ruby static code analyzer 主要用來 format coding style

Installation

Add following line to Gemfile.rb

gem 'rubocop', require: false

Configuration

Config 可以參考 github 上的 Config 資料夾

裡面有三個檔案

  • default.yml(主要的)
  • enabled.yml(預設開啟的)
  • disabled.yml(預設關掉的)

改好後命名為 .rubocop.yml 放在 repo 裡,當你執行 rubocop 指令的時候就會讀取這個檔案的設定開始檢查語法

以下是我自己用的 Rules

把一些比較麻煩的 rules disable 掉了

AllCops:
Exclude:
- 'db/migrate/*'
- 'vendor/**/*'
Rails:
Enabled: true

Rails/HasAndBelongsToMany:
Enabled: false

Bundler/OrderedGems:
Enabled: false

Style/ClassAndModuleChildren:
Enabled: false

Style/ConditionalAssignment:
Enabled: false

Style/Documentation:
Enabled: false

Style/FrozenStringLiteralComment:
Enabled: false

Style/Next:
Enabled: false

Style/GuardClause:
Enabled: false

Metrics/LineLength:
Enabled: false

Metrics/BlockLength:
Enabled: false

Metrics/MethodLength:
Enabled: false

Metrics/AbcSize:
Enabled: false

rubocop 可以幫你自動修正一些語法,只要加上 --auto-correct 參數

rubocop --auto-correct

但是有時候想要一步一步修語法,我只想修正有關 Style 的語法,就要加上 --only 參數,其他以此類推

rubocop --auto-correct --only Style
rubocop --auto-correct --only HashSyntax
rubocop --auto-correct --only StringLiterals

Rake task

如果要整合 travis ci 在每次 code push 的時候檢查語法的話,就要把 rubocop 寫成 rake task,然後寫成 rake default 會跑的 task

lib/tasks/rubocop.rake 加上這幾行

begin
require 'rubocop/rake_task'

RuboCop::RakeTask.new

rescue LoadError # rubocop:disable Lint/HandleExceptions
end

然後修改一下 Rakefile

require_relative 'config/application'

Rails.application.load_tasks
task default: [:rubocop]

這樣當你打 rake 的時候就會自動幫你檢查語法了

要是有不懂的名詞可以查 Official document

· 2 min read

在 Ruby on rails 裡面

通常都是因為要做檔案權限控管

所以才會使用 send_file 這個 method

如果不需要做檔案下載的權限控管的話

直接把檔案放在 public 資料夾即可

有 access control 的檔案下載可以參考這篇 carrierwave secure upload 這樣做完後你的 model 裡就會有一個 download method

來幫你讀檔再用 send_file 來送出去

app/controllers/challenges_controller.rb

def download
send_file file_path, disposition: 'inline'
end

重點有兩個

  1. :disposition 參數用來指定是 inline 還是 attachment,default 是 attachment,所以要指定成 inline
  2. 設定 :type,設定 HTTP content type,瀏覽器知道要怎麼呈現這個檔案,就是所謂的 preview,通常這個參數可以不用設,它會自動從 :filename 裡抓取 file extension 並選擇適當的 MIME type 當作 HTTP content type

#Reference

· One min read

這篇主要是紀錄對 Carrierwave 寫 db/seeds 的方法

單一檔案

Model 是 Material 其中 attachment 欄位是紀錄檔案的欄位

app/models/material.rb

class Material < ApplicationRecord
mount_uploader :attachment, AttachmentUploader
end

通常會把測試的檔案放在 /test/fixtures/ 資料夾下

我有一個檔案路徑在

  • /test/fixtures/magic

db/seeds.rb

material = Material.new()
material.attachment = File.new(File.join("test/fixtures/files/","magic"))
material.save!

多個檔案

Database 是使用 sqlite

所以是用 string 格式來存檔案資訊

官方 issue

我有兩個檔案路徑在

  • /test/fixtures/magic
  • /test/fixtures/gdb.txt

app/models/challenge.rb

class Challenge < ApplicationRecord
mount_uploaders :attachments, AttachmentUploader
end

db/seeds.rb

challenge = Challenge.new()
attachments = [ "magic", "gdb.txt" ]
attachments.map! do | attachment |
attachment = File.new(File.join("test/fixtures/files/",attachment))
end
challenge.attachments = attachments
challenge.save!