# CRUD建立&一些原理(完) ## edit/update 先在index.html.erb加上編輯的連結 ```erb <h1>Hello World!!</h1> <%= link_to "新增",new_book_path %> <% @books.each do |book|%> <%= link_to book.title,book_path %> <%= link_to "編輯",edit_book_path(book) %> <% end%> ``` edit_book_path後面加上(book),讓他找得到book的id。 回到controller寫edit的action ```ruby def edit @book = Book.find(params[:id]) end ``` 有沒有覺得很熟悉,沒錯直接複製show的就好了,他們都是去找特定id的頁面。 再來寫update的action,一樣也是複製貼上,這次複製create的內容,再一點點修改。 ```ruby def update @book = Book.find(params[:id]) if @book.update(book_params) redirect_to books_path else render :edit end end ``` update的資料要先清洗過,render換成edit頁面。 再來寫view,建立edit.html.erb ```erb <h1>編輯</h1> <%= form_with model:@book do |form| %> <div>標題:<%=form.text_field :title %></div> <div>內容:<%=form.text_area :content %></div> <div>價錢:<%=form.text_field :price %></div> <%= form.submit "編輯商品"%> <% end %> ``` 有沒有覺得很眼熟,沒錯,跟new的view一樣,複製貼上換上編輯看個字而已。 這兩個的code重複使用的時候,可以建立一個檔案,讓他們去render。 建立_form.html.erb。名字可隨意取,但是最前面要加上_ ```erb <%= form_with model:book do |form| %> <div>標題:<%=form.text_field :title %></div> <div>內容:<%=form.text_area :content %></div> <div>價錢:<%=form.text_field :price %></div> <%= form.submit %> <% end %> ``` 注意的兩點,把實體變數變成一般的變數,@book => book 。 再來是submit的內容因為略有不同,所以刪掉讓submit自動生字。 這時候的new.html.erb/edit.html.erb ```erb <h1>新增</h1> <%= render "form", book: @book %> ``` ```erb <h1>編輯</h1> <%= render "form", book: @book %> ``` render _form.html.erb的內容,然後將變數book指定成@book。 ## destroy 先在index的view寫上刪除的連結 ```erb <h1>Hello World!!</h1> <%= link_to "新增",new_book_path %> <% @books.each do |book|%> <%= link_to book.title,book_path %> <%= link_to "編輯",edit_book_path(book) %> <%= link_to "刪除",book_path %> <% end%> ``` 當你點擊刪除的時候,你會發現你的網頁會跑向show的頁面。 ![](https://i.imgur.com/lEHPnVu.png) ![](https://i.imgur.com/lhuRrau.png) rails routes明明寫著Perfix也是book。 ![](https://i.imgur.com/0t1ePqP.png) 在這裡show/update/destroy都是共用book_path,我們要再後面加上method,來區分它們。 ```erb <h1>Hello World!!</h1> <%= link_to "新增",new_book_path %> <% @books.each do |book|%> <%= link_to book.title,book_path %> <%= link_to "編輯",edit_book_path(book) %> <%= link_to "刪除",book_path,method: "delete" %> <% end%> ``` 為了避免使用者按了就直接刪除,給他加一個警告確認 book_path可以簡寫成book ```erb <h1>Hello World!!</h1> <%= link_to "新增",new_book_path %> <% @books.each do |book|%> <%= link_to book.title,book %> <%= link_to "編輯",edit_book_path(book) %> <%= link_to "刪除",book,method: "delete" ,data: {confirm: "是否刪除?"} %> <% end%> ``` ![](https://i.imgur.com/7OknBnu.png) 按下去後看到眼熟的紅色框框,Unknown action,代表我們做對方向了,補上destroy action ![](https://i.imgur.com/1FSAE66.png) ```ruby class BooksController < ApplicationController def destroy @book = Book.find(params[:id]) @book.destroy redirect_to books_path end end ``` 這樣刪除就完成了,到這邊CRUD的功能已經具備,但是如果仔細一看,會發現```@book = Book.find(params[:id])```這行code一直不斷重複使用。 當你相同的東西一直重複使用的時候,就應該把他寫成一個方法,讓大家都能使用。 ```ruby private def find_book @book = Book.find(params[:id]) end ``` 但是如果只是這樣還不夠,難道我們要一直重複呼喚這個方法。 在Rails有一個寫法叫做before_action,他會讓方法直接默認的在action裡使用過,不用在多個action一直重複寫這方法。 before_action放在最上面,要在action之前執行 ```ruby class BooksController < ApplicationController before_action :find_book,only: [:show, :edit, :update, :destroy] def index @books = Book.order(id: :desc) end . . . end ``` before_action有兩種寫法,only是只有這些action執行方法,另一個except則是除了這些action以外通通都要執行。 ```[:show, :edit, :update, :destroy]```這四個action的```@book = Book.find(params[:id])```就可以刪掉了。 CRUD的建立就此完成,最後放上controller全部內容,感謝閱讀。 ```ruby= class BooksController < ApplicationController before_action :find_book,only: [:show, :edit, :update, :destroy] def index @books = Book.order(id: :desc) end def new @book = Book.new end def create @book = Book.new(book_params) if @book.save redirect_to books_path else render :new end end def show end def edit end def update if @book.update(book_params) redirect_to books_path else render :edit end end def destroy @book.destroy redirect_to books_path end private def book_params params.require(:book).permit(:title,:content,:price) end def find_book @book = Book.find(params[:id]) end end ```