Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Carrierwave with a one to many relation between models

Stage

Image a gallery application. I have two models Handcraft and Photos. One handcraft may have many photos, suppose I have models like this:

  • Handcraft(name:string)
  • Photo(filename:string, description:string, ...)

In _form.html.erb of handcrafts, there is:

<%= form_for @handcraft, html: {multipart: true} do |f| %>
  # ... other model fields

  <div class="field">
    <%= f.label :photo %><br />
    <%= f.file_field :photo %>
  </div>

  # ... submit button
<% end %>

handcraft.rb looks like this:

class Handcraft < ActiveRecord::Base
  attr_accessible :photo
  has_many :photos
  mount_uploader :photo, PhotoUploader
  # ... 
end

photo_uploader.rb:

class PhotoUploader < CarrierWave::Uploader::Base

  include CarrierWave::RMagick

  storage :file

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  version :thumb do
    process :resize_to_limit => [100, 100]
  end

  def extension_white_list
    %w(jpg jpeg gif png)
  end
end

Problem

When I submit form, it throws this error:

NoMethodError (undefined method `photo_will_change!' for #<Handcraft:0xb66de424>):

Question

How should I use/configure Carrierwave in this case?

like image 562
Israel Avatar asked Oct 31 '12 23:10

Israel


1 Answers

You need to mount the uploader on the field that will store the filename, so your models should look like

class Handcraft < ActiveRecord::Base
  attr_accessible :name
  has_many :photos
  # ... 
end

class Photo < ActiveRecord::Base
  attr_accessible :filename, :description
  mount_uploader :filename, PhotoUploader
  # ... 
end

and then as it seems you'll be creating the photos through the handcraft form, you should add

accepts_nested_attributes_for :photos

in your Handcraft class

Then your form will look something like

<%= form_for @handcraft, html: {multipart: true} do |f| %>
  # ... other model fields

  <%= f.fields_for :photos do |photo| %>
    <%= photo.label :photo %><br />
    <%= photo.file_field :photo %>
  <% end %>

  # ... submit button
<% end %>

For the form to display fields for photo, you'll need your Handcraft instance to have photos created, this can be done in your new method in the HandcraftsController like that:

def new
  @handcraft = Handcraft.new
  4.times { @handcraft.photos.build }
end

This will make 4 (arbitrary number) fields availables in your form, if somehow you want the user to dynamically add new photos in your form, have a look at nested_form

like image 182
pjam Avatar answered Nov 02 '22 22:11

pjam