Reputation: 1135
I am working on an admin interface where I have images and heroes. The hero table consists in only two columns: id and image_id. I would like to be able to add and remove images to the hero table.
I have a select_to_hero and select_from hero action and view which display either all images not already connected or all existing heroes and both work, but the add_to_hero and remove_from_hero actions, which I use to create a new or destroy an existing association do not work.
Hero.rb Model
class Hero < ActiveRecord::Base
attr_accessible :image_id
belongs_to :image
end
Image.rb Model
class Image < ActiveRecord::Base
attr_accessible :alt, :author, :copyright, :file_name, :title
has_one :hero
mount_uploader :file_name, ImageUploader
end
Select_from_hero.html.erb
<% @heroes.each do |hero| %>
<%= link_to(image_tag(hero.image.file_name.url(:thumb), {:action => 'remove_from_hero', :id => hero, :hero => @hero}) %>
<% end %>
Select_to_hero.html.erb
<% @images.each do |image| %>
<%= link_to(image_tag(image.file_name.url(:thumb), {:action => 'add_to_hero', :id => image, :hero => @hero}) %>
<% end %>
images_controller.rb
def add_to_hero
@hero.image << Image.find(params[:id]) unless @hero.image.include?(Image.find(params[:id]))
if @hero.save
..
else
render :action => 'select_to_hero'
end
end
def remove_from_hero
@hero.image.delete(Image.find(params[:id]))
if @hero.save
..
else
render :action => 'select_from_hero'
end
end
With this setting I get:
NoMethodError in Admin::ImagesController#add_to_hero
undefined method `image' for nil:NilClass
and
NoMethodError in Admin::ImagesController#remove_from_hero
undefined method `image' for nil:NilClass
But I can query an existing association:
> Hero.find(2).image
Hero Load (0.3ms) SELECT `heroes`.* FROM `heroes` WHERE `heroes`.`id` = ? LIMIT 1 [["id", 2]]
Image Load (0.3ms) SELECT `images`.* FROM `images` WHERE `images`.`id` = 1 LIMIT 1
=> #<Image id: 1, file_name: "red.jpg", title: "blu", alt: "yellow", author: "John", copyright: "Jane", created_at: "2019-01-29 19:50:25", updated_at: "2019-01-29 19:50:25">
How can I get this working?
Routes
namespace :admin do
resources :heroes
match '/images/select_to_hero', :to => 'images#select_to_hero', :as => :select_to_hero
match '/images/select_from_hero', :to => 'images#select_from_hero', :as => :select_from_hero
resources :images
match '/images/add_to_hero/:id', :to => 'images#add_to_hero', :as => :add_to_hero
match '/images/remove_from_hero/:id', :to => 'images#remove_from_hero', :as => :remove_from_hero
...
end
I had to move the select_to_hero
and select_from_hero
routes above resources :images
or a call would have triggered the show
action.
Upvotes: 0
Views: 93
Reputation: 1135
Thanks to the always helpful @vasilisa I figured out a way to solve my problem. I had to use:
<% @images.each do |image| %>
<%= link_to(image_tag(image.file_name.url(:thumb)), {:action => 'add_to_hero', :id => image, :image_id => image}) %>
<% end %>
in my view and:
def add_to_hero
@hero = Hero.new(:image_id => params[:id])
if @hero.save
...
else
render :action => 'select_to_hero'
end
end
in my controller action.
This works, since in my case I only needed to declare an image as a hero by creating a new entry into Hero or to remove a hero declaration by destroying an entry in Hero.
Thanks all for their advice.
Upvotes: 0
Reputation: 6263
follow up your last comment about your add_to_action, I would like to suggest solution below
Select_to_hero.html.erb, change :hero and send only the id of hero like this below
<% @images.each do |image| %>
<%= link_to(image_tag(image.file_name.url(:thumb), {:action => 'add_to_hero', :id => image, :hero_id => @hero.id}) %>
<% end %>
images_controller.rb, find the hero first from the hero_id
def add_to_hero
@hero = Hero.find(params[:hero_id])
@hero.image << Image.find(params[:id]) unless @hero.image.include?(Image.find(params[:id]))
if @hero.save
..
else
render :action => 'select_to_hero'
end
end
Upvotes: 1