---
title: Rails 101 練習筆記
tags: note
---
# Rails 101 練習筆記
## 連結
改寫 `migration`
[官方文件](https://guides.rubyonrails.org/active_record_migrations.html)
全棧營
> 解答的版本是舊版的,ruby 是 2.3
- [x] [招聘網站](https://fullstack.qzy.camp/courses/29/syllabus)
- [GitHub](https://github.com/gn2481/job_listing)
- [x] [電商網站](https://fullstack.qzy.camp/courses/31/syllabus)
- [GitHub](https://github.com/gn2481/shopping_website)
## [招聘網站](https://fullstack.qzy.camp/courses/29/syllabus)
### 筆記
> 主要紀錄沒有使用過的語法,或是使用的方式
---
:one: `link_to` 的 `path` 可以帶入參數,將參數塞在網址上。
> *可以放在分頁、搜尋、排序的實作*
```htmlmixed=
<!-- views/jobs/index -->
<%= link_to "按照薪資上限排序", jobs_path(order: "by_upper_bound"), class: "dropdown-item" %>
<%= link_to "按照底薪排序", jobs_path(order: "by_lower_bound"), class: "dropdown-item" %>
<%= link_to "按照建立時間排序", jobs_path(order: "by_created_time"), class: "dropdown-item" %>
```

`link_to` 的 `path` ,後面可帶上網址的參數,上述用於判斷資料的排序方式(在 `controller` ,定義傳進來的參數 (這裡是 `params[:order]`) 是什麼來下排序方式)
```ruby=
# controllers/jobs_controller
def index
# @jobs = Job.where(is_hidden: false).order("created_at DESC")
@jobs = case params[:order]
when 'by_upper_bound'
Job.published.order('wage_upper_bound DESC')
when 'by_lower_bound'
Job.published.order('wage_lower_bound DESC')
else
Job.published.recent
end
end
```
---
:two:
### 遇到的問題
1. bootstrap webpacker 安裝方式不熟
[詹昇 Rails Webpack 筆記](/10wfeoedToONL7oqd8BLfg?view)
[我的筆記 (rails 6)](/4osXt6pqRbSolMzWb696Gw)
---
2. 安裝 foreman 時!又遇到 thor 版本的問題!
```ruby=
# gem file
gem 'foreman', '~> 0.82.0'
```

主要是 `foreman` 0.82 ,的 dependency ,`thor` 衝突了,一般來說不要指定版本(by Gimmy 大大)就可以囉!
:::info
:gem: 詹昇:遇到這問題就是把指定版本號拿掉,跑一次 `bundle`,在看哪個版本能過,然後指定用那個版本號
:::
若是已經被鎖定 thor 的版本號,找到最佳的版本號(兩者皆可運作的版本好)。
```ruby=
# gemfile
gem 'thor', '~> 1.0'
```
然後將被 lock 住的版本更新!
`bundle install thor`
就可以囉~
---
3. 轉頁的語法
Rails 6 :
```ruby=
redirect_back fallback_location: root_path, notice: '職缺發布成功'
```
之前的版本 :
```ruby=
redirect :back(fallback_location: root_path), notice: '職缺發布成功'
```
:::danger
:bulb: 在 Rails 6 使用 `redirect :back` ,會噴錯。
:::
---
## [電商網站](https://fullstack.qzy.camp/courses/31/syllabus)
### 購物車
> 跟第一次接觸到的不一樣,所以紀錄做法,記錄一下做法
建立 `Cart`、`Cart_item` 的 model
使用者可以按下按鈕將商品加入購物車裡,
首先使用者要先有購物車,而且這個購物車不能隨著跳頁而消失 ==(所以要存進session裡)==,而當點下加入購物車按鈕,會在 `cart` 裡 增加一個 `cart_item`
- 方法一,可以在`session`只存購物車的id,再用`current_cart` 的方法抓資料出來。
- 優:+1: 購物車的資料會寫進`db`,基本上不會有消失的情況。
- 缺:-1: 就是在 `db`,塞了很多垃圾
- 方法二,可以將整個購物車的內容通通用成 `hash` 存進 `session` 裡,要做訂單時,再將 `hash` 轉出來變成 `product` 的物件。
- 優:+1: 效能比較好,因為不會進 `db`
- 缺:-1: 因為是整個 `hash`,所以可能會不見,不過到時候使用者在慢慢點回去就好 XD
方法一:
```ruby=
# product_controller.rb
# 記得要去 routes.rb 增加路徑
# 最終結果,期望網址是 product/:id/add_to_cart 時,可以將商品加入購物車
def add_to_cart
product = Product.find(params[:id])
current_cart.add_product_to_cart(product)
end
```
想想,這些方法要定在哪裡,要怎麼寫?
:::spoiler 解答
```ruby=
# application_controller.rb
# 寫成 helper view 才能用
helper_method :current_cart
def current_cart
@current_cart ||= find_cart
end
private
def find_cart
# 先找一下有沒有已存在的 cart
cart = Cart.find_by(id: session[:cart_id])
# 如果沒有要做給他
if cart.blank?
cart = Cart.create
# 做完要把 cart.id 寫入 session 中!
session[:cart_id] = cart.id
end
# 回傳 cart!
return cart
end
```
```ruby=
# cart.rb
# 待修改
def add_product_to_cart(product)
cart_item = self.cart_items.new
cart_item.product_id = product.id
cart_item.quantity = 1
cart_item.save
end
# 為了有上述這些方法可以用,要記得設定 model 關聯性
```
`cart has_many cart_items`
`cart_items has_many products`
:::
---
方法二:(施工中)
:::spoiler WIP
```ruby=
session[:cart_item] = {'apple' : 1,
'banana': 3,
......}
```
:::
## :question: 購物車與購物車物品與商品的關係!
背景提示
在製作購物車頁面途中,製作 table 時,
```htmlmixed=
<tbody>
<% current_cart.cart_items.each do |cart_item| %>
<tr>
<td>
<%= link_to product_path(cart_item.product) do %>
<% if cart_item.product.image.present? %>
<%= image_tag(cart_item.product.image.thumb.url, class: "thumbnail" ) %>
<% else %>
<%= image_tag("http://placehold.it/200x200&text=No_Pic", class: "thumbnail" ) %>
<% end %>
<% end %>
</td>
<td>
<%= link_to cart_item.product.title, product_path(cart_item.product) %>
</td>
<td>
<%= cart_item.product.price %>
</td>
<td>
<%= cart_item.quantity %>
</td>
</tr>
<% end %>
</tbody>
```
問題:
`cart` 與 `product` 是多對多的關係,透過 (`cart_item` 這張表格),為何不能使用 `current_cart.products` ,要取用,[購買商品數量] 一定要使用 `cart_item.quantity`
解答:
這樣會取不到 購買數量的值,若使用`current_cart.products`,會變成要使用兩個 `block`去處理,反而更麻煩!