--- 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" %> ``` ![](https://i.imgur.com/EYMlGYb.png) `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' ``` ![](https://i.imgur.com/OUhOwnM.png) 主要是 `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`去處理,反而更麻煩!