Kurt Hsu's blog

The Rails developer in taiwan.


  • 首頁

  • 標籤

  • 分類

  • 歸檔

[Devops]安裝數據庫和Nginx + Passenger 網站服務器

發表於 2018-04-29 更新於 2019-12-29 分類於 Devops

安裝數據庫


MySQL

$ sudo apt-get install mysql-common mysql-client libmysqlclient-dev mysql-server
過程中會要設定root密碼

進入mysql console:
$ mysql -u root -p

建立數據庫:
$ CREATE DATABASE rails_recipes CHARACTER SET utf8mb4;
rails_recipes名稱可以自己取不能有-這個符號
$ exit離開mysql console

PostgreSQL

$ sudo apt-get install postgresql libpq-dev postgresql-contrib

修改postgres這個帳號的密碼:
sudo -u postgres psql
\password
然後輸入密碼和確認密碼
\q離開

建立數據庫:
sudo -u postgres createdb rails_recipes
rails_recipes名稱可以自己取不能有-這個符號

安装 Nginx + Passenger 網站服務器


在本機開發的時候,我們使用 puma 這一套由 Ruby 寫的網站服務器,無論是靜態檔案(圖片/CSS/JS)或是會進到 Rails 處理的動態網頁,一律都是由 puma 來處理。

在正式production 環境中,我們會用更高效能的網站服務器來處理,其中Nginx是目前最流行的網站服務器(用C語言開發的),可以非常高效能地提供靜態檔案,效能是純Ruby 網站服務器的數十倍以上。因此像圖檔/CSS/JS等等靜態資源,都會由 Nginx 處理。至於 Rails 動態網頁的部分,我們會安裝 Passenger 這個 Nginx 的擴充模組來執行 Ruby 程序:Nginx 會把非靜態檔案的 HTTP Request 轉交給 Passenger 來處理。

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
$ sudo apt-get install -y apt-transport-https ca-certificates
$ sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger xenial main > /etc/apt/sources.list.d/passenger.list'
$ sudo apt-get update
$ sudo apt-get install -y nginx-extras passenger

現在直接在遊覽器打自己主機的位置應該可以看到Welcome to nginx!頁面了

[Ubuntu]Ubuntu系統更新和安装 Linux 和 Rails 套件

發表於 2018-04-27 更新於 2019-10-03 分類於 Devops , Ubuntu

更新和安装 Linux 套件


apt-get是 Ubuntu 内建的套件管理工具與 Mac 上的 homebrew雷同,在雲端伺服器上更新系統套件清單,然後升級。

sudo apt-get update
sudo apt-get upgrade -f - Do you want to continue? [Y/n]直接按enter

設定時區:
可以先看預設時區
$ date
應該跟自己的時間對不起來,如果想設定台灣時區:
sudo dpkg-reconfigure tzdata
選擇Asia > TaiPei後再次檢查
$ date
應該就會是剛剛的時間加八小時(UTF+8)了!

接這一行安裝Rails需要的東西:
sudo apt-get install -y build-essential git-core bison openssl libreadline6-dev curl zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 autoconf libc6-dev libpcre3-dev libcurl4-nss-dev libxml2-dev libxslt-dev imagemagick nodejs libffi-dev
一樣Do you want to continue? [Y/n]直接按enter

小補充:
如果$ apt-get update卡在0% [Connecting to security.ubuntu.com (2001:67c:1360:8001::17)]可能是因為ipv6不穩,可以設定只使用apt-get 只使用 ipv4,編輯這個檔案:

/etc/sysctl.conf
1
2
3
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

最後執行$ sudo sysctl -p再重新run$ sudo apt-get update

安装 Ruby


使用Brightbox安裝Ruby套件:
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:brightbox/ruby-ng
$ sudo apt-get update
$ sudo apt-get install ruby2.4 ruby2.4-dev
$ ruby -v
顯示ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux-gnu]代表成功

安裝 Bundler:
$ sudo gem install bundler --no-ri --no-rdoc
–no-ri –no-rdoc 参数的意思是不需要安装文档,可以节省安装时间

[Github]SSH key 自動驗證到自己的雲端機器上

發表於 2018-04-27 更新於 2019-12-29 分類於 Github

Github在做git push或者要登入雲端機的時候都需要打密碼,我們可以利用SSH key來直接操作或登入。

原理是非對稱加密中有公鑰(public key)和密鑰(private key):

透過公鑰加密的密文, 只有密鑰能夠解開
透過密鑰加密的密文, 只有公鑰能夠解開

如果本機端沒有公鑰和密鑰請執行:
$ ssh-keygen -t rsa
即會產生
公鑰~/.ssh/id_rsa.pub
密鑰~/.ssh/id_rsa
這兩個檔案
密鑰請一定要保管好!

再來登入自己的機器
$ ssh kurt@xxx.xxx.xxx.xx
$ mkdir ~/.ssh
$ touch ~/.ssh/authorized_keys

把剛剛本機端的印出來
$ cat ~/.ssh/id_rsa.pub

在雲端上貼入剛剛~/.ssh/authorized_keys這個檔案

$ chmod 700 ~/.ssh
$ chmod 644 ~/.ssh/authorized_keys

應該就大功告成了!
如果不知道chmod請參考我另一篇文章[Linux]Linux 權限管理

不允許遠端登入


假設不允許root使用遠端登入:

用root權限編輯 /etc/ssh/sshd_config
修改PermitRootLogin no這樣就不允許root選端登入。

如果你有設好用公鑰登入,也可以修改PasswordAuthentication no,這樣就不能用輸入密碼的方式登入。這樣服務器會安全的多,因為駭客就不能猜密碼了。只是說如果你不是用自己的電腦想要登入服務器,沒有公鑰檔案的話就沒有辦法登入了。

最後
sudo service ssh restart
就會重啟 SSH 套用設定。

[Linux]Linux 權限管理

發表於 2018-04-27 更新於 2019-12-29 分類於 Linux

在租用雲端服務的時候像linode會空給一台機器自行管理,其實跟當初自己買mac一樣只是mac可以直接有很多介面化的操作,而當我們要去管理雲端機器的時候大多只能用terminal去下指令,這時候熟悉Linux的基本指令就很重要。

而權限管理也是保護機器上資料重要的一環,不能讓別人隨意取得root權限,不然其他人就可以肆意的控制這台機器了!

關於root


如果申請好雲端機器可以直接在terminal用ssh遠端登入:
$ ssh root@xxx.xxx.xxx.xx

在機器裡面可以創造很多使用者,root則是內建且一開始擁有所有權限的,所以我們創造一個使用者叫kurt:
$ adduser kurt
頭兩次是設定密碼和確認密碼,設定完之後一直按enter即可。

P.S:$ sudo adduser --disabled-password username可以創造一個沒有密碼的用戶,用SSH key登入更安全,可以參考這篇:[Github]SSH key 自動驗證到自己的Github上

$ exit可以logout回到本地端,此時可以直接用kurt這個身份登入:
$ ssh kurt@xxx.xxx.xxx.xx

當然也可以在這時候隨意切換其他使用者,root也行只要知道使用者密碼的話:
$ su - root
如果要離開一樣:
$ exit
這時候是會彈回kurt這個使用者,在下一次exit才會回到本地端唷!

sudo 权限


假設我們在root創了一個檔案abc.txt,然後想用kurt指令去修改該檔案:
$ vim /root/abc.txt
會跟你說沒有權限修改Permission denied的錯誤訊息。

這時候要登回root去改實在太麻煩了,可以利用指令把kurt擁有sudo權限:
gpasswd -a kurt sudo

此時要改檔案就下:
sudo vim /root/abc.txt
就擁有權限可以改動此檔案了

更改檔案權限


首先在root下查看此目錄中的檔案權限:
$ ls -la
螢幕快照 2018-04-27 下午6.00.19.png

第二個root是檔案擁有人
第三個root是群組,預設跟自己的名字是一樣的

再來前十碼第一碼d是目錄-是文件
再來第二碼開始每三碼代表一個權限,分別是自己的,群組的,其他使用者的
r代表可以讀w代表可以寫入x代表可以執行-代表沒有權限

如何更改檔案擁有人和群組?
$ chown kurt:kurt abc.txt
將abc.txt這個檔案所有人設定為kurt,群組設定為kurt。

如何更改檔案使用權限?
chmod 644 abc.txt
會把這個檔案變為
rw-r--r--

這裡
r=4
w=2
x=1
所以第一個數字是6 = 2 + 4代表rw-
第二個單純的是4代表r--

想知道如果利用SSH KEY免打密碼登入到自己的雲端機器請參考這篇:[Github]SSH key 自動驗證到自己的Github上

[Rails]第三方測試站串金流 (failed)

發表於 2018-04-27 更新於 2019-08-21 分類於 Rails

這次是失敗的先敘述原因和結果:
1.Pay2Go測試平台雖然是可以正常開啟和使用但似乎不能用了?因為在套件pay2go他敘述了『智付寶第三方金流業務已轉移到智付通,請改用 spgateway』。

2.Pay2Go和Spgateway官方API document和實作上幾乎是一樣的,Spgateway甚至還標明了版本更新日期是2018-01-03,但測試站要串的API需要給予『CheckValue』這個文件沒提到的參數,要怎麼算出來的我不知道,所以最終是一直卡在這關。

實作紀錄


這是Pay2go測試平台,這是Spgateway測試平台,兩個都可以直接簡單註冊資料不必填真實,創立商店後主要需拿到:
商店編號 MerchantID
串些金鑰 HashKey
串些金鑰 HashIV

可以直接把任何繳費服務都打開(預設應該也都是全部開啟),再來就是去裝套件了。

套件上pay2go和 spgateway兩個文件寫的幾乎一樣,這裡用pay2go做示範。

Gemfile
1
gem "pay2go"

$ bundle install

設定整合模式

config/environments/development.rb
1
2
3
4
5
6
Rails.application.configure do
...(略)
config.after_initialize do
Pay2go.integration_mode = :development
end
end

config/environments/production.rb
1
2
3
4
5
6
Rails.application.configure do
...(略)
config.after_initialize do
Pay2go.integration_mode = :production
end
end

加入 pay2go 的 API key
$ touch config/initializers/pay2go.rb

config/initializers/pay2go.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Pay2go.setup do |pay2go|
if Rails.env.development?
pay2go.merchant_id = "1234567" # 放測試站的 key

pay2go.hash_key = "xxxxxxxx"
pay2go.hash_iv = "xxxxxxxx"
pay2go.service_url = "https://cpayment.pay2go.com/MPG/mpg_gateway"
else
pay2go.merchant_id = "1234567" # 放正式站的 key

pay2go.hash_key = "xxxxxxxx"
pay2go.hash_iv = "xxxxxxxx"
pay2go.service_url = "https://payment.pay2go.com/MPG/mpg_gateway"
end
end

此時先把測試站的MerchantID(商店編號), key 和 iv 貼上去

再來設定信用卡付款按鈕
$ mkdir app/services

app/services/pay2go_service.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Pay2goService
def initialize(order)
@order = order
@timestamp = order.created_at.to_i
@merchant_order_no = "#{order.id}s#{Time.now.strftime("%Y%m%d%H%M%S")}"
@total_price = order.total
end

def check_value
d = Digest::SHA256.hexdigest(url_params).upcase
end

def url_params
"HashKey=#{Pay2go.hash_key}&Amt=#{@total_price}&MerchantID=#{Pay2go.merchant_id}&MerchantOrderNo=#{@merchant_order_no}&TimeStamp=#{@timestamp}&Version=1.1&HashIV=#{Pay2go.hash_iv}"
end
end

重開 rails server

新增按鈕的partial

_pay_with_credit_card.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%= form_tag Pay2go.service_url, method: :post do  %>
<%= hidden_field_tag "MerchantID", Pay2go.merchant_id %>
<%= hidden_field_tag "HashKey", Pay2go.hash_key %>
<%= hidden_field_tag "HashIV", Pay2go.hash_iv %>
<%= hidden_field_tag "LoginType", "0" %>
<%= hidden_field_tag "RespondType", "JSON" %>
<%= hidden_field_tag "Version", "1.1" %>

<%= hidden_field_tag "ItemDesc", "order_sample" %>
<%= hidden_field_tag "MerchantOrderNo", "#{order.id}s#{Time.now.strftime("%Y%m%d%H%M%S")}" %>
<%= hidden_field_tag "TimeStamp", order.created_at.to_i %>
<%= hidden_field_tag "Amt", order.total %>

<%= hidden_field_tag "CREDIT", "1" %>
<%= hidden_field_tag "ReturnURL", pay2go_cc_notify_order_url(order.token) %>
<%= hidden_field_tag "CheckValue", Pay2goService.new(order).check_value %>

<%= submit_tag "使用信用卡付款", class: "btn btn-danger btn-lg btn-default" %>
<% end %>

然後在想要的頁面的地方render上去

view.html.erb
1
<%= render "pay_with_credit_card", order: @order %>

加上 controller 的 callbacks

some_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...(略)
protect_from_forgery except: :pay2go_cc_notify

...(略)

def pay2go_cc_notify
@order = Order.find_by_token(params[:id])

if params["Status"] == "SUCCESS"
@order.make_payment!

if @order.is_paid?
flash[:notice] = "信用卡付款成功"
redirect_to account_orders_path
else
render text: "信用卡失敗"
end
else
render text: "交易失敗"
end
end

修改routes

config/routes.rb
1
2
3
resources :comes do
post :pay2go_cc_notify
end

發現post出去的網址即使剛剛在config/initializers/pay2go.rb裡面設定pay2go.service_url測試網址,但他依然post出去的是舊的測試平台網址『https://capi.pay2go.com/MPG/mpg_gateway』。

我就直接把form_tag的action寫死:

_pay_with_credit_card.html.erb
1
2
3
<%= form_tag action="https://cpayment.pay2go.com/MPG/mpg_gateway", method: :post do  %>
…(略)
<% end %>

但測試結果是不行的。

網上很多舊的教學文章引導到這裡但是實際上post出去是失敗的,後來我開始去看官方文件,Pay2Go的說需要:
MerchantID 商店代號
Version 版本請帶1.0
TradeInfo 交易資料 AES 加密
TradeSha 交易資料 SHA256 加密

但我嘗試了許久終究會是TradeSha錯誤,網上也說很有可能是AES 加密先錯誤造成SHA256 加密錯誤,我也試了不下幾個方法,最後才看到文件上說要用Spgateway的套件去做才猜測是不是Pay2Go的套件和測試平台不能用了。

再來換成Spgateway的套件和他的測試平台去實作,那就去把action位置改為Spgateway的測試API吧!

_pay_with_credit_card.html.erb
1
2
3
<%= form_tag action="https://ccore.spgateway.com/MPG/mpg_gateway", method: :post do  %>
…(略)
<% end %>

再到Spgateway測試平台像Pay2Go一樣建立商店取得商店代號和key,把信用卡服務什麼的都打開,然後去修改config/initializers/pay2go.rb把商店代號和key填進去。

結果報的錯誤是檢查碼錯誤...,檢查碼到底是什麼官方文件上都沒有寫,後來一個一個刪除去找發現是CheckValue這個東西有問題,因為當把他從_pay_with_credit_card.html.erb移除後會報錯檢查碼不可空白...,CheckValue又在官方文件上都沒有提到…就這樣嘗試了幾回合後發現自己真的無法通靈就先告一段落了…

此次是我錯誤的結果紀錄,但我發現串正式機的話似乎不用驗證CheckValue,但要串正式機建立真實商店就不是這麼容易了…
那其他的串金流也沒有像這個這麽好串可以callback回來我的localhost,也許是錯過最好的時代了…(苦笑)

[Rails]從零做起 simple line bot

發表於 2018-04-25 更新於 2019-08-21 分類於 Rails , Line

設置我們自己的第一個API


首先我們先創造一個專案並且利用postman做出第一個簡單的api
$ rails new simple line bot

到router裡面建立入口

routes.rb
1
2
3
Rails.application.routes.draw do
post "webhook", to: "welcome#webhook"
end

建立controller
$ rails g controller welcome

welcome_controller.rb
1
2
3
4
5
class WelcomeController < ApplicationController
def webhook
head: ok 200
end
end

至少要回傳一個簡單的東西這邊是 head: ok 200

再來打開server
$ rails s

利用postman的post送出一個請求到本地端剛剛的街口localhost:3000/webhook

這時候看剛剛terminal小黑窗會看到因為CSRF而出現的錯誤
Can’t verify CSRF token authenticity

這是遊覽器的一個保護機制,如果沒有這個token則有心人士可以不透過遊覽器去呼叫網站的API,例如資料填一填post到一個網址即可用別人的信用卡幫自己買東西

為了先解決這個問題先修改controller

welcome_controller.rb
1
2
3
4
5
6
class WelcomeController < ApplicationController
protect_from_forgery with: :null_session
def webhook
head: ok 200
end
end

這時候postman在post到localhost:3000/webhook應該就可以得到回傳的200了!

部署到heroku


到heroku官方網站 https://dashboard.heroku.com/apps 創造一個app
跟github的指令一樣到自己的專案push上去

在本地端查看server log
$ heroku logs -t

然後用postman測試post到https://{app name}.herokuapp.com/webhook
terminal應該也可以看到回傳了ok 200

申請並且設定line bot


首先到line developers https://developers.line.me/en/ 申請一個bot channel

在Basic information找到Channel secret
在Messaging settings找到Channel access token等等要使用

然後在Messaging settings設定
Use webhooks設定為Enabled
Webhook URL Requires SSL設定網址,就是剛剛heroku的網址https://{app name}.herokuapp.com/webhook。

所以其實把自己的機器人加為好友後傳訊息給他會先到Line的server端,就是這裡的後台,他會post到剛剛的Webhook URL就是自己的heroku伺服器,這時候看自己的heroku logs應該也會看到訊息!

抓取回傳一樣對話的訊息:


如果我們現在發對話給我們機器人,自己的heroku logs應該會看到訊息而訊息格式如下(此為官方範例):

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
{
"events": [
{
"replyToken": "0f3779fba3b349968c5d07db31eab56f",
"type": "message",
"timestamp": 1462629479859,
"source": {
"type": "user",
"userId": "U4af4980629…"
},
"message": {
"id": "325708",
"type": "text",
"text": "Hello, world"
}
},
{
"replyToken": "8cf9239d56244f4197887e939187e19e",
"type": "follow",
"timestamp": 1462629479859,
"source": {
"type": "user",
"userId": "U4af4980629..."
}
}
]
}

我們其實就可以拿這個回傳的params做事情了!

假設我們只是要拿對話可以先print 出來在server logs上面觀察

welcome_controller.rb
1
2
3
4
5
6
7
class WelcomeController < ApplicationController
protect_from_forgery with: :null_session
def webhook
puts params["events"].first["message"]["text"]
head: ok 200
end
end

此時應該看得到自己傳的訊息。

安裝line-bot-sdk-ruby套件並使用


line-bot-sdk-ruby官方文件https://github.com/line/line-bot-sdk-ruby

Gemfile 安裝完後bundle install 修改controller

welcome_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class WelcomeController < ApplicationController
protect_from_forgery with: :null_session
def webhook
# Line Bot API 物件初始化
client = Line::Bot::Client.new { |config|
config.channel_secret = ENV['line_channel_secret']
config.channel_token = ENV['line_channel_token']
}

reply_token = params['events'][0]['replyToken']

response_message = {
type: "text",
text: params["events"].first["message"]["text"]
}

client.reply_message(reply_token, response_message)
head :ok
end
end

client.reply_message會再去post到LINE server的套件function
格式就是帶兩個參數在上面都寫明了!

這部分就先commit再push到heroku上面吧!

注意到這裡需要設定ENV環境參數在下一步講解。

設定heroku環境參數


到heroku網帳進去到自己bot的專案裡面 > settiing > 把Config Variables打開
到LINE developers自己的channel找到Channel secret和Channel access token

新增兩個選項:
line_channel_secret - Channel secret
line_channel_token - Channel access token

這樣就大功告成摟!

[Rails]Gemfile specified some Ruby version and Rubygems updates

發表於 2018-04-24 更新於 2020-01-19 分類於 Rails

與別人協同專案的時候常會遇到版本問題,在clone下來專案的時候有下$ bundle install可能會遇到:
Your Ruby version is 2.3.1, but your Gemfile specified 2.4.4

此例子是他想要ruby版本是 2.4.4但目前是 2.3.1

這時候利用rvm可以先做下列動作:
$ rvm list 可以查詢目前本地端有的版本

此時如果沒有指定的版本則下:
$ rvm install ruby-x.x.x x.x.x是想要安裝的版本

如果已經有或安裝好要使用則下:
$ vm use ruby-x.x.x 後面可以加–default來預設以後都用這個版本

再來下:
$ bundle install 他可能會說找不到指令(zsh: command not found: bundle)代表還沒安裝bundle(以前用rails new太順不知道這原來是一個gem XD)

如果沒有安裝的話就下:
$ gem install bundler 安裝bundler

這時候基本上可以bundle install成功了,但是下$ rails s開啟伺服器的時候又給以下訊息:
Warning: You’re using Rubygems 2.0.14.1 with Spring. Upgrade to at least Rubygems 2.1.0 and run `gem pristine –all` for better startup performance.
Your Ruby version is 2.0.0, but your Gemfile specified 2.4.4

一開始想WTF我不是已經指定Ruby version是2.4.4了嗎?我就開始往Rubygems的問題去找,關鍵字是下update Rubygems,有提供很多種方法我是用最簡單的下:
$ gem update

更新了許久的時間終於專案的環境架設成功,可以開始開發!

[Rails] 初探 helper 和 partial

發表於 2018-04-24 更新於 2019-08-21 分類於 Rails

這兩個都是來避免過多邏輯在view裡面把view搞亂了,或者是重複性太高違反了Don’t repeat yourself(DRY)程式碼不重複的精神。

先說使用情境:

helper使用在較單一情況且需要與原始程式碼進行一些邏輯混合的情況,例如if else,或者只是要format一些數據但卻沒辦法一眼讀懂。

partial則使用在超過兩個頁面的地方,例如重複用的表單,每個頁面幾乎都要用到的header和footer等。

Helper使用


例如要實作出可以由商品的圖片進入到商品的詳細內容,但如果沒有商品的圖片則是show出預設圖片,我們可以這樣一步一步來:

index.html.erb
1
2
3
4
5
6
7
<% @products.each do |product| %>
<% if product.image.present? %>
<%= image_tag(product.image.medium.url, class: "thumbnail") %>
<% else %>
<%= image_tag("http://placehold.it/400x400&text=No Pic", class: "thumbnail") %>
<% end %>
<% end %>

寫成這樣實在讓人無法一眼明瞭,開始建立helper:

products_helper.rb
1
2
3
4
5
6
7
8
9
def render_product_image_link(product)
link_to product_path(product) do
if product.image.present?
image_tag(product.image.medium.url)
else
image_tag("http://placehold.it/400x400&text=No Pic")
end
end
end

再來修改剛剛的view:

index.html.erb
1
2
3
<% @products.each do |product| %>
<%= render_product_image_link(product) %>
<% end %>

頓時覺得空氣清淨許多!

記住helper是全域的,即使在別的頁面也可以使用!

Partial使用


例如header,不會想要在每個頁面下都先有好幾行程式碼開頭,所以先做出一個Partial:

_header.html.erb
1
<center><h1>Header</h1></center>

然後放在layout的html裡面,通常是application.html.erb

application.html.erb
1
2
3
4
<body>
<%= render "header" %>
<%= yield %>
</body>

這樣每個頁面上面都會顧頂有header這個東西了!

1.不只能放在layout裡面,任何一個view都可以把他render進來。
2.如果沒給他絕對路徑會自動去app/views的這個資料夾找尋。
3.建議可以做歸類像header和footer自己創一個資料夾放進去,例如commen則<%= render “common/header” %>就好。

[Rails]scss and javascript in specific page

發表於 2018-04-23 更新於 2019-08-21 分類於 Rails

參考文章:
Rails實戰聖經

指定引入CSS的方法


在application.css的default值都會因為有require_tree .把底下所有的檔案透過Asset Pipeline全部壓縮成一個css檔案。

但我們想要做得到是:
1.不透過require_tree .引入全部檔案只想引入我們想要的
2.在特定的頁面只執行想要的css

第一點把require_tree拿掉自己一個個require或import近來當然沒問題。
第二點是引入的東西都是全局的,意思是說當rails g controller的時候專案雖然會自動幫你產生出css檔案,但這些檔案是互通的,因為他們終究會被壓縮成單一隻js和css。

方法有很多但這篇記錄兩個,並且用SCSS做示範:

第一個方法給予每個template獨特的id

我們可以在view的最外層包一個id:

home.html.erb
1
2
3
<div id="home">
<h1 class="title">Hello world</h1>
</div>

然後在他自己的scss裡面寫上:

home.scss
1
2
3
4
5
#home {
h1 {
color: red;
}
}

這樣的優點依然可以利用專案製造出來的scss很快速的找到該頁面的css,但要怎麼想id名稱就是一道題目了。

且有人會說那application.scss還不是都要import一堆檔案為什麼要捨棄require_tree這個方便的東西。
我認為當scss檔案一多規劃變得很複雜之外最實用的一個狀況是在全面更新或停用一隻scss檔案的時候舊的檔案可以依然保留在app/assets/stylesheets/這個目錄下不用被移除,不然如何處理舊的scss也是一道難題。

第二個方法利用 stylesheet_link_tag

1.一定要移除require_tree
2.要去修改config/initializers/assets.rb這隻檔案

全域的東西依然先引進app/stylessheets/application.scss這隻檔案,此時如果沒把require_tree拿掉他又會把它吃進去了!

假設有一隻檔案要單獨在一個頁面引入,例如style.scss,則進行以下修改:

config/initializers/assets.rb
1
2
3
4
5
6
7
8
9
10
11
# Be sure to restart your server when you modify this file.

# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'

# Add additional assets to the asset load path
# Rails.application.config.assets.paths << Emoji.images_path

# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
Rails.application.config.assets.precompile += %w( style.scss )

重啟server

然後到我們的view裡面:

view.html.erb
1
2
3
4
<div id="view">
<h1 class="title">Hello world</h1>
</div>
<%= stylesheet_link_tag "style" %>

就可以了!

目前記錄下這兩種方法,管理css方式一定有更多手法也必須對應專案的需求,就看看到時候遇到的情況如何了。

指定引入Javascript的方法


原因跟css一樣是想擺脫require_tree .把底下所有的檔案透過Asset Pipeline全部壓縮成一個js檔案。

方法一如同css的方法二利用 javascript_include_tag

假設有一隻檔案要單獨在一個頁面引入,例如welcome.js,則進行以下修改:

config/initializers/assets.rb
1
2
3
4
5
6
7
8
9
10
11
# Be sure to restart your server when you modify this file.

# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'

# Add additional assets to the asset load path
# Rails.application.config.assets.paths << Emoji.images_path

# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
Rails.application.config.assets.precompile += %w( welcome.js )

重啟server

然後到我們的view裡面:

view.html.erb
1
2
3
4
<div id="view">
<h1 class="title">Hello world</h1>
</div>
<%= javascript_include_tag "welcome" %>

就可以了!

此時與引入在application.js最大的不同是,每次重進這個頁面這行js就會在執行一次,也就是每次進這個頁面這個檔案的js就會執行一次!

第二個方法是利用TURBOLINKS

這邊先記錄下來這三篇可以參考的文章:
Rails Guides

ORGANIZING JAVASCRIPT IN RAILS APPLICATION WITH TURBOLINKS

Page Specific Javascript in Ruby on Rails

[Rails]image file in asset or public

發表於 2018-04-22 更新於 2020-01-20 分類於 Rails

網上查了很多文章,一直對於圖片檔案要放在app/asset/images裡面還是public裡面感到很疑惑,應用起來也踢到很多鐵板,這邊把自己的問題記錄下來,也可以做最簡單的應用!

什麼時候放在app/asset/images裡面?

幾乎所有的圖片都放在asset裡面就好了,之後搭配關於Asset Pipeline的$ rake assets:precompile指令即可,後面會再提到。

什麼時候放在public裡面?

其實public也不止能拿來放圖片,他有點像一個倉庫專門放置靜態頁面的東西。

靜態頁面大多是指404.html找不到頁面或者是500.html伺服器有狀況比較少用到且沒有什麼功能的頁面,此時給予這些靜態頁面的圖片放置在這裡比較正確。

實作


假設我們在asset/images裡面放了一個圖片image.jpg:

用scss引入當background

stylesheet
1
background-image: image-url("imag.jpg");

當作圖片的話可以直接在view裡寫上rails的helper:

view
1
<%= image_tag("imag.jpg", class:"images") %>

如果有錯誤的話嘗試換上雙引號

Asset Pipeline


Asset Pipeline是什麼?可以直接先參考Rails 實戰聖經。

白話的說Rails會自己把所有css和javascript壓縮成一個檔案不製造過多的網頁request。
處理圖片的時候會給圖片名稱一段編碼,以後只要更新過圖片即使是一模一樣的也不會造成catch!

請檢查自己deploy的環境,例如本地端或者是上heroku是不用自己下指令壓縮的!他在執行伺服器的時候就會自動執行,不然正常來講需要下指令:

$ rake assets:precompile
這時候檔案會產生在public/assets/下。

當然要刪除的話就下:
$ rake assets:clobber

實戰聖經補充:

注意,如果在開發模式下執行了rake assets:precompile,那麼因為放在public/assets/下的靜態檔案會優先丟給瀏覽器,所以這時候再修改app/assets下的原始碼會沒有作用。所以,開發時請記得要刪除這個目錄。

參考文章:
Rails 實戰聖經

1…789…18

Kurt Hsu

Progress One Percent Every Day
171 文章
55 分類
163 標籤
RSS
© 2020 Kurt Hsu
由 Hexo 強力驅動 v3.8.0
|
主題 – NexT.Muse v7.3.0