我需要能够点击一个按钮或一个链接,将改变一个模型中的布尔属性从假到真,而不使用一个形式。页面上已经有一个表单创建了模型的一个新示例,我不希望两个表单之间的冲突出现在一个页面上。所以,我有一个ItemResponse
模型,布尔值为accept
-我希望我的链接“接受报价”在部分更改为真,并刷新页面。
我的控制器:
class ItemResponsesController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy, :accept]
before_action :correct_user, only: :destroy
def create
@item_response = current_user.item_responses.build(response_params)
if @item_response.save
flash[:success] = "Item Response created!"
redirect_back(fallback_location: root_url)
else
@item = @item_response.item
render 'items/show', status: :unprocessable_entity
end
end
def destroy
@item_response.destroy
flash[:success] = "Item Response deleted"
redirect_back_or_to( root_url, status: :see_other )
end
def accept
@item_response.update_attribute(:accept, true)
if @item_response.save
flash[:success] = "Item Response Accepted!"
redirect_back(fallback_location: root_url)
else
@item = @item_response.item
render 'items/show', status: unprocessable_entity
end
end
private
def response_params
params.require(:item_response).permit(:item_id, :message, :offer, :pickuporship)
end
def correct_user
@item_response = current_user.item_responses.find_by(id: params[:id])
redirect_to root_url, status: :see_other if @item_response.nil?
end
end
我的路线:
Rails.application.routes.draw do
default_url_options :host => "localhost:3000"
root "static_pages#home"
get "/help", to: "static_pages#help"
get "/about", to: "static_pages#about"
get "/contact", to: "static_pages#contact"
get "/signup", to: "users#new"
get "/login", to: "sessions#new"
post "/login", to: "sessions#create"
delete "/logout",to: "sessions#destroy"
resources :users
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :items, only: [:create, :destroy, :index, :show]
resources :looking_for_items, only: [:create, :destroy, :index, :show]
resources :item_responses, only: [:create, :destroy, :accept]
resources :item_responses do
member do
get "accept"
end
end
resources :looking_for_responses, only: [:create, :destroy]
end
我的部分答案是:
<li id="item_response-<%= item_response.id %>">
<%= link_to gravatar_for(item_response.user, size: 30), item_response.user %>
<span class="user"><%= link_to item_response.user.name, item_response.user %></span>
<span class="message"><%= item_response.message %></span>
<span class="offer"><strong>Offering $<%= item_response.offer %></strong></span>
<span class="pickuporship">
<% if item_response.pickuporship %>
<%= "🛻 Will Pick Up Item" %>
<% else %>
<%= "📦 Want Item Shipped" %>
<% end %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(item_response.created_at) %> ago.
<% if current_user?(item_response.user) %>
<%= link_to "delete response", item_response, data: { "turbo-method": :delete,
"turbo-confirm": "Are you sure?"} %>
<% end %>
</span>
<% if item_response.accept %>
<%= "Accepted!" %>
<% else %>
<%= "Not Accepted" %>
<% end %>
<%= link_to "Accept Offer", accept_item_response_path(item_response) %>
</li>
最后,我的ItemResponse模型:
class ItemResponse < ApplicationRecord
belongs_to :user
belongs_to :item
default_scope -> { order(created_at: :desc) }
attribute :accept, :boolean, default: false
validates :user_id, presence: true
validates :item_id, presence: true
validates :message, length: { maximum: 2000 }
validates :offer, presence: true,
numericality: { only_integer: true },
inclusion: 0..10000
validates :pickuporship, inclusion: [true, false]
validate :offer_matches_item_asking_price
validate :pickuporship_matches_seller_preference
validates :accept, inclusion: [true, false]
def offer_matches_item_asking_price
theitem = Item.find(item_id)
errors.add(:base, "The seller is not accepting OBOs - please match their asking price") unless ( theitem.obo == true ) || ( theitem.askingprice == offer )
end
def pickuporship_matches_seller_preference
theitem = Item.find(item_id)
errors.add(:base, "Please select a pickup or ship option that matches the seller's preference") unless ( theitem.pickup == true && pickuporship == true ) || ( theitem.willship == true && pickuporship == false )
end
end
当我尝试点击上述链接时,我得到一个错误:undefined method
update_attribute' for nil:NilClass`
所以@item_response有问题-它期待一个表单?我真的需要把这个做成一个表格吗?或者我需要使用turbolinks就像我删除/销毁的东西?
1条答案
按热度按时间hgb9j2n61#
所以@item_response有问题-它期待一个表单?
不。你只是在调用一个你没有定义的示例变量的方法。这是Ruby中的经典初学者脚枪。
我需要能够点击一个按钮或一个链接,将改变一个模型中的布尔属性从假到真,而不使用一个形式。
错了。
实际上,你绝对想要使用表单,因为这是一个non-idempotent action,用来更新服务器上的资源。
使用浏览器发送非幂等请求(POST)是使用表单完成的。链接发送GET请求。GET请求存储在浏览器历史记录中,点击后退按钮不会导致意外后果。
在Rails中,你可以用
button_to
来处理这个问题,它可以创建一个只有一个按钮的表单,或者用Rails UJS或Turbo处理程序来处理data-method
或data-turbo-method
方法的链接。真实的的区别只是后者使用了一些JavaScript技巧来创建一个没有附加到DOM的表单并提交它。这是一种不太鲁棒和可访问的方法,但可以在表单内部使用(HTML中不允许嵌套表单)。
你实际上应该做的: