简体   繁体   中英

rails link_to posts to incorrect id - why?

I want my User to be able to change a boolean on a Share that they own, but my attempt at implementation updates the wrong record.

When I go to the show page for an Item with id:7 , my controller loads the associated Share objects by looking for Share s that have item_id set to 7. When I then click the Hide or Show buttons, my code updates the associated Share 's active attribute, and then redirects to that same Item .

But if I go to the show page for an Item with id:3 , and click those same buttons, my code redirects to and updates the active attribute for the Share with item_id:7 , instead of item_id:3 . Can anyone give me an idea as to why this is happening?

My Share model:

class Share < ActiveRecord::Base
 belongs_to :user
 belongs_to :item

 def activate
  self.active = true
  save
 end

 def deactivate
  self.active = false
  save
 end
end

My Item model:

 class Item < ActiveRecord::Base
  has_many :shares
 end

In my ItemsController#show action, I have this:

def show
 @item = Item.friendly.find(params[:id])
 @owned_share = current_user.shares.find_by(item_id: @item.id)
end

In my SharesController , I have this:

def activate
 @owned_share = current_user.shares.find_by(params[:item_id])
 @owned_share.activate
 respond_to do |format|
  format.html { redirect_to item_path(@owned_share.item) }
  format.json { render :index, status: :ok, location: @owned_share }
 end
end

def deactivate
 @owned_share = current_user.shares.find_by(params[:item_id])
 @owned_share.deactivate
 respond_to do |format|
  format.html { redirect_to item_path(@owned_share.item) }
  format.json { render :index, status: :ok, location: @owned_share }
 end
end

And in my Item show view, I have this:

<% if @owned_share.active == true %>
 <div class="eight wide column">
  <%= link_to "Hide", share_deactivate_path(@owned_share.item), class: "button wide-button functional-red-button", method: :post %>
 </div>
<% else %>
 <div class="eight wide column">
  <%= link_to "Show", share_activate_path(@owned_share.item), class: "button wide-button functional-mint-button", method: :post %>
 </div>
<% end %>

As stated in the comments, the param you're receiving isn't item_id , but share_id , that's why despite you modify your query adding the attribute which to look for, it doesn't give you the expected result.

Update the param which to use for getting user's share, like:

@owned_share = current_user.shares.find_by(item_id: params[:share_id])

Although in this case isn't clear why you're using share_id to look for an item_id, most probably you could update that part too.

As both actions share some specific functionality, you could make just one that just updates the active attribute "flipping" its value:

# model
def toggle_active
  update(active: !active)
end

# controller
def update_active_status
  @owned_share = current_user.shares.find_by(item_id: params[:share_id])
  @owned_share.toggle_active
  respond_to do |format|
    format.html { redirect_to item_path(@owned_share.item) }
    format.json { render :index, status: :ok, location: @owned_share }
  end
end

It gets the current user's shares active value and alternate it by using ! . Notice that if they don't have a default value, a negation of nil returns true.

!true  # false
!false # true
!nil   # true

Note @owned_share.active == true can also be @owned_share.active? or @owned_share.active .

Because this:

@owned_share = current_user.shares.find_by(params[:item_id])

should be:

@owned_share = current_user.shares.find_by_item_id(params[:item_id])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM