--- title: 20200807 AstroCamp rails 一起做 ptt ! tags: Astro Camp, rails --- # 20200807 AstroCamp rails 一起做 ptt! ## 分析可能需要的功能 1. 看板需要的東西 Board title:string intro:text deleted_at:datetime, 預設值:nil/null, 下索引(用硬碟空間換取搜尋時間) (較常被查詢的才要下索引值) state:[default:noraml,disable,hidden] Model 是大寫單數 tables 是小寫複數 controller 通常是複數 --- ## 碰到的問題 ### 為何同一controller裡有相同@實體變數? ![](https://i.imgur.com/H3b2O2O.png) 行為:當創建看板時,將new.html裡的form打包成params,POST到create(action)的裡 因為HTTP本身沒有狀態,雖然在new方法裡有將@board,指定為Board.new,但是在網址切換時,此@board狀態並不會被儲存。 但因為有將params POST到creat,所以可以在下一個creat方法裡再將@board指定為Board.new(params[:board]) (所以其實可以把兩個變數設為不同的名字...但後續製作上會有問題) ### 無窮迴圈 ``` class Board < ApplicationRecord def self.all where(deleted_at: nil) end ``` 可能where方法也有呼叫all,導致無窮迴圈。 --- 要複習的觀念 1. 實體方法,類別方法的差異? 1. 使用的地方? 2. **寫法?** 2. proc是把block物件化,後面可以接block ## 選取資料 Scope(定義選取資料時的範圍) 已經被做好了! ``` module ActiveRecord class Base def self.scope(scope_name,callback) end end end class Book <ActiveRecord::Base scope :available, -> {where(delete_at: nil)} end ``` scope 讓一開始在抓資料的時候就不要抓到已被軟刪除的資料 scope可以連段 ``` scope :not_hidden, -> {where(stauts: off_line)} scope :not_deleted, -> {where(deleted_at: nil)} ``` 上面可以找出未被刪除且上線狀態不是隱藏的看板! default_scope所有在找資料的時候都先執行設定的條件 ``` default_scope {where(deleted_at: nil)} scope :available, -> {where(deleted_at: nil)} ``` 相當於下面這一塊 ``` def self.available where(deleted_at: nil) end ``` 想取消要手動 => unscope super 會呼叫上層同名的方法 ``` def hello puts a end def hello super puts b end ``` 印出a,b 安裝了[paranoia](https://rubygems.org/gems/paranoia)套件,所以上面都不用做了 = =""[github](https://github.com/rubysherpas/paranoia/) belongs_to -> has_many 做出(並不是真的把board跟post的model做關聯,只是做出了一些方法,讓你可以找出一些上層的東西) 1. .posts 方法 會去抓某看板的所有文章(會去抓board_id) 翻譯:`select * from posts where board_id=XXX` 如果剛開始建立的欄位不是`board_id`,而是`b_id`,要自己手動加上`foreign_key` ``` has_many :posts, foreign_key: b_id ``` 建立文章(從看板的角度) ``` bb = Board.find(9) bb.posts.create(title: "aa") ``` 網址要設計! 不好的網址設計: ``` Rails.application.routes.draw do resources :boards do resources :posts end end ``` 如果只是要找文章,不需要去找到boars_id,因為在Posts的資料裡面post.id不會重複。 進階的寫法:把文章包進看板裡,把不需要的功能抽掉 ``` Rails.application.routes.draw do resources :boards do resources :posts, only: [:index, :new, :create] end resources :posts, except: [:index, :new, :create] end ``` ``` Rails.application.routes.draw do resources :boards do resources :posts, shallow: true end ``` ## 第四天 ### 如果上層被刪掉了,那下層的資料怎麼辦? * 資料有相依性 * rails 預設若下層有fk(forgin key)指向上層,上層砍不掉! * 有dependent方法 :delete :destroy :nullify ``` class Board < ApplicationRecord acts_as_paranoid has_many :posts, dependent: :destroy validates :title, presence: true, length: {minimum: 2} ``` 其實用了paranoia,因為不會真的刪除資料,所以dependent有無設定根本不會觸發。 ### 資料:實體層跟抽象層? * 實體層:打開SQL軟體看到、設定的東西,都是實體層 ### 驗證資料 #### 想要產生文章流水編號 ``` list = [*'a'..'z',*'A'..'Z',*1..9] list = list - [I','l',1,'o','O','0'] list.sample(8).join ``` #### uniquness,資料某欄位不能重複 1. 配合scope ``` class Holiday < ApplicationRecord validates :name, uniqueness: { scope: :year, message: "should happen once per year" } end ``` name或是year必須是uniq。 2. case_sensitive 大小寫是否有區分 ``` class Person < ApplicationRecord validates :name, uniqueness: { case_sensitive: false } end ``` ## 加入了文章流水號,驗證設置成必須填入,且不能與其他資料重複後...... ### 新的資料再也寫不進去了! 因為seial_generator是設定在before_create,所以在寫入時,在驗證階段時因為文章流水號都是nil,跟之前前面新增的文章重複了,所以寫不進去了! [Callback回呼流程](https://railsbook.tw/chapters/19-model-validation-and-callback.html) ![](https://i.imgur.com/Vj9hF1M.png) ### 要寫rake,請系統幫忙做全域的更新! 寫在 lib/task/xxx.rake裡 **注意:執行rake task前,vaildates那邊必須先allow_nil: true** 過程:rake 先把資料塞進去,但還沒save,所以在驗證時狀態還是nil,會失敗! ``` namespace :db do desc "更新文章序號" task :update_post_serial => :environment do puts "-----------------" puts " updating serial " puts "-----------------" Post.where(serial: nil).each do |pt| pt.update(serial: serial_generator(10)) print "." end puts "done!" end private def serial_generator(n) [*'a'..'z', *'A'..'Z', *0..9].sample(n).join end end ``` 呼叫方法時,要看recicever是誰 方法只會找同層的 private 方法不能明確指出recicever是誰 ### recicever 各個self會印出誰? ![](https://i.imgur.com/WW4fWJk.png) method_missing 掙扎 我們看到的錯誤訊息其實是上上上..層的一個methd_missing的一個方法! ## 使用者! > 資料正規化 > 讓每個資料表存放他該有的資料就好! > 盡量不要有重複的資料,如果大家輸入的資料重複性很高,不如做另一個表格用代號的方式給他。 > > 第一正規化(1NF): > 一個欄位只能有一筆資料! > > > 第二正規化(2NF): > 1. 滿足1NF > 2. 去除部分相依性 > > 第三正規化(3NF): > 再看看有沒有重複的資料欄位! ### 分析資料! model: User - account:string - password:string - email:string - nickname:string - gender:string - state:string - deleted_at:datetime:index model: Profile - 簽名檔 - 名片檔 `add_reference :post, :user`