2017年5月12日 星期五

第三次上五倍紅寶石rails課 5/12

http://railsbook.tw/chapters/13-crud-part-1.html
這次的課有點不知道要怎麼有條理的做筆記,所以只記了一些我當初最一開始搞不清楚的東西比方說裡面什麼東西都沒有可是會動的action,或是不知道打哪來的params,還有充滿謎的form_for

想當初我第一次看controller的時候都很疑惑為什麼有些裡面明明什麼都沒有寫,可是為什麼還是有作用,後來才知道有些是因為before_action做了,外加預設都會幫你去render同名的view出來
#像這種不知道幹嘛的action
  def show
  end
那如果今天我把上面的index action也砍掉會發生什麼事呢?
答案是什麼事都不會發生XD
他還是會顯示出index(驚)
原因是因為雖然你沒有action,但是他還是會繼續去找同名的view
所以如果今天一個action什麼特別的事都沒有做,是可以不寫action的。
(不過我應該還是會照寫XD)
另外public資料夾裡面的檔案的優先權會在最前面,因為他不需要經過routes,如果你今天放一個index檔案在裡面,你在首頁看到的會是public裡面的index,而不是view裡面那一個

params

  get "/candidates/:id", to: "candidates#show"
比方routes像上面那樣子寫的話,一開始的時候其實我知道params[:id]可以抓到id,但我並不知道那個id到底是哪來的,為什麼這樣子就可以抓得到,等我發現原來是url裡面有的已經是又過一陣子的事了….(遠目)
<ActionController::Parameters {"controller"=>"candidates", "action"=>"show", "id"=>"1"} permitted: false>
有一個是我這次上課才知道的事,像上面這種你會發現不管是params[:id]還是params[“id”]你都可以抓到1,這是因為rails有特別做一些處理讓你可以不管是字串還是symbol都抓的到id。
不然原本ruby的hash用字串或symbol是當成不同的key,因為內部是用”===”來比較key是否一樣

resource / resources

如果今天routes是用resources :candidates,會得到下面這樣
        Prefix Verb   URI Pattern                    Controller#Action
          root GET    /                              welcome#index
    candidates GET    /candidates(.:format)          candidates#index
               POST   /candidates(.:format)          candidates#create
 new_candidate GET    /candidates/new(.:format)      candidates#new
edit_candidate GET    /candidates/:id/edit(.:format) candidates#edit
     candidate GET    /candidates/:id(.:format)      candidates#show
               PATCH  /candidates/:id(.:format)      candidates#update
               PUT    /candidates/:id(.:format)      candidates#update
               DELETE /candidates/:id(.:format)      candidates#destroy
如果你改成resources :candidate上面的網址和controller都會變成單數,所以一開始生成controller的時候就要用單數的,不過慣例上controller是用複數
如果是用resource :candidates的話,和上面會長得差不多,但通通不會有:id接在後面

form_for

雖然很好用,但是想當初對我來說是最大的黑魔法,很多東西我都不知道怎麼來的,畢竟我連html都不熟
<%= form_for @candidate do |f| %>
  姓名: <%= f.text_field :name %><br/>
  政黨: <%= f.text_field :party %><br/>
  年紀: <%= f.text_field :age %><br/>
  政見: <%= f.text_area :politics %><br/>
  <%= f.submit %>
<% end %>
> f.class #=>ActionView::Helpers::FormBuilder
form_for建出來的表單裡面會包含一個authenticity_token,在下一個步驟的時候(比方new到create的時候)會是檢查這一串東西是不是自己生出來的,會被擋掉,可以某種程度上防止有人亂來
(等我知道有這東西大概是半年後了吧XD)
<input type="hidden" name="authenticity_token" value="nGETyiPlewIYWrhrWI2M60V0oSxzXjy7eiNhh9MQTuN/7vg++OLprwmk3E6BgYFwbrgFOFWKECYBRE/ZH9hbxw==">

form params的值

<ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"nMX+QtDWxq0wp/9gR9HAmF5VtG0cAqW4vI4BWVVQM8N/ShW2C9FUACFZm0We3c0DdZkQeTrWiSXH6S8HmZgm5w==", "candidate"=>{"name"=>"tests", "party"=>"fdsf", "age"=>"fds", "politics"=>"fds"}, "commit"=>"Create Candidate", "controller"=>"candidates", "action"=>"create"} permitted: false>
以前我並不知道這些params是哪來的
我只知道params[:candidate][:name] 可以抓到我剛剛在form裡面填的名子,但我不知道到底哪來的
到我自己發現原來是來自name,而name是form_for幫忙按照規則建好的又是好一陣子以後了。
當初我真的很搞不清楚各種params到底打哪來的,對我來說都像是莫名冒出來的。
<form class="new_candidate" id="new_candidate" action="/candidates" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="authenticity_token" value="gbNo9SfPSRpfCjlOUC60LtHy6o08C0ZcVUQaGgFwoTWFWqHKwO+IO1GksoAVvQ8icy1CMdcE+0NZTpc9kERR8w==" />
  姓名: <input type="text" name="candidate[name]" id="candidate_name" /><br/>
  政黨: <input type="text" name="candidate[party]" id="candidate_party" /><br/>
  年紀: <input type="text" name="candidate[age]" id="candidate_age" /><br/>
  政見: <textarea name="candidate[politics]" id="candidate_politics">
</textarea><br/>
  <input type="submit" name="commit" value="Create Candidate" data-disable-with="Create Candidate" />
</form>

strong parameters

為了防止被亂塞東西進來,所以rails4之後有了strong parameter,只有允許的幾個欄位會被處理
params.require(:candidate).permit(:name, :party, :age, :politics)
不過下面這樣就不用管strong parameter了,因為不是整坨吃進去,但是一般不會這樣子寫就是了
name = params[:candidate][:name]
party = params[:candidate][:party]

驗證錯誤後的行為

通常會像下面這樣處理
  def create
    @candidate = Candidate.new(cadidates_params)
    if @candidate.save
      redirect_to candidates_path
    else
      render 'new'
    end
  end
為什麼不用redirect_to呢?雖然功能上不會有任何問題,但是資料會被清掉,這是很惹人厭的UX體驗。
render只是借用new這個action的template,action沒有被重新執行一次,你人還是在create裡,所以本來填的資料都還會在。
另外create本身不需要view,那為什麼要用實體變數呢?因為不這樣子的話你render “new”的時候就會炸掉了,因為new需要@candidate這個變數。
如果只是create本身的話你變數取什麼都不會有影響(其實我之前都沒想過這問題XD)
不過你可能會看到你的view好像歪掉了,因為form_for會在驗證錯誤的時候多塞了一個field_with_errors
<div class="field_with_errors"><input type="text" value="" name="candidate[name]" id="candidate_name"></div>
.field_with_errors {
  display: inline;
}
#config/application.rb
config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag }
Written with StackEdit.

沒有留言:

張貼留言