ajax和instance variable的問題


#1

ajax新手的問題。
我有一個在views/list/show.html.erb render的partial: _search_books.html.erb,可以正常的顯示@list的值(list#show產生)

然後在_search_book.html.erb中的form_tag,我用ajax的方式執行一個爬蟲去爬資料,得到的資料再拿去填在partial下方的div裡的一個’/search/show_result’的partial。爬蟲功能是正常的,但在/search/show_result裡,有用到@list,ajax呼叫完就會出錯。

簡而言之,就是原本在views/lists/show.html.erb 的其中一個partial中,@list是正常的,但是ajax過後, show.html.erb裡的partial會出現錯誤

ActionView::Template::Error (undefined method `name’ for nil:NilClass):
20: <% end %>
21:
22: <%= render ‘shared/spinner’ %>
23: <%= @list.name %>

@list.name這行我只是拿來測試的,發現原本是可以顯示的,但是ajax後就會找不到@list
google了一整天還是找不到方法,
我的form_tag大概長這樣

<%= form_tag(’/search_book’, id: ‘item-lookup-form’, remote: true, method: :get) do %>

完整檔案在此:
https://github.com/iansrc0811/forum_web1/blob/add_new_articles/app/views/lists/_search_books.html.erb

有找到一篇stackoveflow,問題和我的很像,可是我看不太懂解答

請問各位前輩該如何解決這個問題?


#2

看了你一些 code … hmm … 先別管 partial 了,你知道複製貼上嗎?(好啦,我只是想用這個梗而已 X"DD )

code 沒看完,單純的猜測原因和簡單解釋一下

[[action]]
def show
  @list = Item.find(params[:id])
end

[[view]]
show.html.erb => _search_books.html.erb

這邊說找得到 @list 非常正常,因為 @ 系列變數會一直用下去
action(產生@) => view(沒引用) => partial(引用@)

然後你 call AJAX 沒有找到 @list 那就會變成

[[action]]
def search
  #任何你做的事情,但少了@list的初始化
end

[[view]]
search.html.erb => _search_books.html.erb (error)

所以就會變成
action(沒產生@) => view(沒引用) => partial(引用@)(error)

或是單純的你的 @list 是沒有找到任何東西的,也就是 search 結果為 nil,你都必須排除掉哩

這邊其實和有沒有用 partial 一點關係都沒有,因為你可以把 view 的 partial 當作是嵌套的副程式,把整個 code 複製貼上到使用的那一頁,應該也是要可以動的才是(除非過 locals 的那種變數)

AJAX 和一般 load 網頁的道理是一樣的,沒有不同,所以檢查你的輸入值,處理流程,自然會得到你相對應的輸出,然而 debug 最基本的:

  1. Rails log 有寫 params 的輸入值,否則 code 內 params[:id] 可能都是 nil,因為連輸入都沒有
  2. action / view 印 @ 系列變數出來看
  3. 設想 @ 沒有值的狀況,是要 redirect 還是顯示無資料
  4. 沒有這項了,因為上面就是『“輸入檢查”,“流程檢查”,“輸出檢查”』,任何程式從小到大全部也就這樣而已

so~ 自己先檢查看看,partial 不一定要用很多,否則你之後無法收斂也不好,一般來說我都會先複製貼上相同的 code 在不同的 view 上,在後期才想辦法收斂成 partial(也才能看出 partial 需要多做哪些判斷來符合所有使用的狀況),否則你要編輯很多檔案,不會很煩咪?尤其開發後面發覺有多種狀況的時候,所以不要過早最佳化,否則你會繞很多圈子和做無用的事情哩


#4

JC前輩您好,
我現在把partial都集中到一個erb檔,真的好看多了XD

後來看了上面的回答很久,才懂為什麼要再初始化一次@list…然後沒錯我就是沒有初始化@list才會出錯,但現在的問題是我不知道要怎麼初始化,google了很久還是沒有頭緒,好像都不是我要的。

views/lists/show.html.erb: 的 form_tag這邊我有使用到lists#search。
show action有正常的初始化( @list = List.find(params[:id] ) 所以沒問題。但是當我在form_tag輸入後送出,會用到search action,但是我不知道怎麼得把當前的@list.id傳到controller再初始化一次@list,所以不知道要怎樣初始化。
所以,
請問要怎麼在當前的show.html.erb取得@list.id,然後把此id傳到 lists_controller中的search action呢?
這邊還是貼一下我的程式碼:
views/lists/show.html.erb:

controllers/lists_controller.rb:

感謝前輩解答,謝謝 :slight_smile:


#5

訊息傳遞在 HTTP 內大概就是 GET 或 POST 兩種,所以先別管 Rails 的 route 了,否則你連基本功都不會就想越級打王

簡單的來說

GET : http://example.tw/action/:id/?kind=123&wtf=234

或是

POST : http://example.tw/action/:id/  +  kind=123&wtf=234

這兩種而已,而 POST 可以還可以增加成為 PATCH / DELETE 兩種 route

這是 HTTP 的基本,而 Rails 的 route 幫你包裝過而已,上面這些基本不用 Rails,一般 HTTP 就可以玩了,類似自己寫 HTML 之類的

再來是你的問題,單純沒去看 doc 不知道把參數過到下一層 & 我不確定你是否有看完我們 youtube 的教學之類的…|||

link_to '傳到下層去' , items_path(:kind => 123 , :wtf => 234)

form_for @item , :method => 'post' , :url => item_path(:id => @item.id , :kind => 123 , :wtf => 234) do
  #...
end

http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to

http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for

這樣就可以把額外的變數輕易地過到下一次層去,而在下個 action 就可以取到 params[:kind]params[:wtf],記得,沒有人會教你看 doc,我看到現在一票教學都沒有人教,所以這邊不管怎樣的問題我都會貼 doc,因為不看 doc 就代表你自己不夠努力,且別人只會在用 doc 去教你而已,你會感覺對方很厲害,但是卻不知這些資訊其實很多地方都可以查到的

form_for(record, options = {}, &block)

這些東西應該在 youtube 內的新手 Ruby 教學內都有,類似 block 使用和傳入值,而 Rails 包裝漂亮一點而已 & 你如果不想過外部變數讓人破解的話,善用 session 或寫到 cache 或 db 內都可以的,大概就這樣唄