Trouble rendering images uploaded with CarrierWave - ruby-on-rails

I'm building a basic Rails 4 application, and seem to have hit a frustrating snag. I've been following the CarrierWave Railscast, and while I'm able to get images to show up on /image/show.html.erb, I've had some difficulties with getting any of the images I've uploaded to display in the gallery each image is associated with.
The strange thing is, there aren't any errors logged. The page loads without any Rails errors coming up in the page or the terminal; the only way I know something is wrong is that the div that images are supposed to appear in doesn't show up at all.
I'm really stumped about this. If you look, the .images div in the show action for galleries renders, but absolutely none of the sub-elements render at all. What am I doing wrong?
Source code here
app/models/image.rb
class Image < ActiveRecord::Base
belongs_to :gallery
mount_uploader :image, ImageUploader
end
app/models/gallery.rb
class Gallery < ActiveRecord::Base
has_many :images
end
app/uploaders/image_uploader.rb
class ImageUploader < 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 => [200, 200]
end
end
apps/views/images/show.html.erb
Below, we can see that images can be rendered without issue, as this is a view for their own respective controller.
<p>
<strong>Title:</strong>
<%= #image.title %>
</p>
<p>
<strong>Description:</strong>
<%= #image.description %>
</p>
<p>
<strong>Image:</strong>
<%= image_tag #image.image_url.to_s %>
</p>
/apps/views/galleries/show.html.erb
This is where everything gets tricky. First off, no matter what I change within the images div, everything within it seems to come up blank regardless. I've tried changing the "for image in #gallery.images" bit several times, but to no avail.
<div id="images">
<% for image in #gallery.images %>
<div class="image">
<%= image_tag image.image_url(:thumb) %>
<%= image.description %>
<div class="name"><%= image.title %></div>
<div class="actions">
<%= link_to "edit", edit_image_path(image) %> |
<%= link_to "remove", image, :confirm => 'Are you sure?', :method => :delete %>
</div>
</div>
<% end %>
<div class="clear"></div>
</div>
<p>
<%= link_to "Add a Painting", new_image_path(:gallery_id => #gallery) %> |
<%= link_to "Remove Gallery", #gallery, :confirm => 'Are you sure?', :method => :delete %> |
<%= link_to "View Galleries", galleries_path %>
</p>

You need to associate the gallery and the image. One option is to pass the gallery_id to the new action like you do now, set it in the controller on the new image, add a hidden field to transport it to the create action and whitelist the parameter there.
The other option is to nest the image routes into the gallery routes like so:
resources :galleries do
resources :images
end
This will create URLs like /galleries/123/images/234 and galleries/1233/images/new. You create links to these page for example with edit_galleries_image_path(#gallery, #image). Again you would need to set the correct gallery_id in images#new on the new image but that should then let form_for generate the right path to the create action where you then have the gallery_id parameter available. Going this way rake routes should come in as a handy tool.

Related

Is there a way to loop through many attached images using active storage

I have installed active storage and I want a Post class or model to have one or many images so I created an association like below:
class Post < ApplicationRecord
has_many_attached :images
end
I can create a post and I have allowed the images in the parameters and I have enabled multiple uploads and the post can be created successfully but when I want to iterate the images on the view like below I get nothing;
<% #post.images.each do |image| %>
<%= image_tag(image) %>
<%end%>
When I try to just display one image without looping like below I get an error saying Can't resolve image into URL: undefined method to_model'`.
<%= image_tag(#post.images) %>
So far that is what I have tried and when I just display the #post.images in an embedded ruby I can get some information like below that indeed the images are there.
Is there anything am doing wrong?
I implemented this previously by doing it this way.
class Post < ApplicationRecord
has_many_attached :images
end
The images for your post should included in the params as such:
def car_params
params.require(:car).permit(:name, :description, :comments, images:[])
end
Then in the views, I looped through the images this way:
<% if #post.images.attached? %>
<% #car.images.each do |image| %>
<li>
<button type="button" >
<%= image_tag(url_for(image)) %>
</button>
</li>
<% end %>
<% end %>
If you want to select one image without looping, then you can select by the index.
<%= image_tag(#post.images[0]) %>
If you seek to loop through, go ahead with the url tag as that works better.

undefined method 'to_model' when linking thumbnail to original image

I'm creating an album that I'm planning to display with Masonry and ImgZoom so that the visitors can have a bigger image when they click on it.
According to ImgZoom, to make the zoom work, you need to do the following:
<a href="path/to/real/image.png">
<img src="path/to/image's/thumbnail.png class="thumbnail" />
</a>
So I generated an uploader, with the following inside it:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
'portfolio/photos'
end
version :thumb do
process :resize_to_fit => [220, nil]
end
end
Everything works perfectly, I can call both the versions without trouble, but when I try to follow ImgZoom's instructions by doing the following:
<%= #portfolio.photos.each do |p| %>
#This is a nested form inside the portfolio form, so I need to do this to get my images
<%= link_to image_tag p.image.thumb.url, p.image %>
or:
<%= link_to p.image do %>
<%= image_tag p.image.thumb.url, :class => 'thumbnail' %>
<% end %>
I'm getting the following error: undefined method 'to_model' for #<ImageUploader:0x0000000c35f4d8>
I found a similar subject on stack overflow but the asker wasn't clear and was invited to ask an other question on the forum, which I couldn't find.
I can individually reach 'p.image' and 'p.image.thumb.url', but I can't make a link from one to another, which would be perfectly doable with simple html.
What am I doing wrong?
Thank you in advance
First, to create the class "thumbnail" in the link, you need to declare it properly. I edited the link:
<%= link_to p.image.url do %>
<%= image_tag p.image.url, class: "thumbnail" %>
<% end %>
Second, you need to check if you created an appropriate route for viewing the image. This can be either done by linking to a static assets properly (as your image is not under "public") or via a template view.
If the files where stored under "public", your way of linking should work just fine.
Check out how image_path works in the docs: image_path (and more)

How can I invoke the create method of an object with another object's id?

I am trying to build a gallery with commenting function. Consider there are 3 classes: Album, Photo, Comment. The relation of these objects are Album has many Photos, Photo has many Comments.
Each Comment is left by registered user, thus in the comment object there are comment_text, user_id, and photo_id (Referring to the photo which the comment belongs).
I am trying to create a comment form under each photo's "show" view. Here is some of the Controller and the Show view:
controllers/photos_controller.rb
class PhotosController < ApplicationController
...
def show
#photo = Photo.find(params[:id])
#new_comment = #photo.comments.build if user_signed_in?
#comment_items = #photo.comments.paginate(page: params[:page])
end
...
end
views/photos/show.html.erb
...
<%= form_for #new_comment, html: {method: :post} do |c| %>
<div class="row">
<div class="span">
<%= image_tag current_user.avatar.url(:thumb) %>
</div>
<div class="span">
<p><%= c.label "Enter your comment here:" %></p>
<p><%= c.text_area :comment_text %></p>
<p><%= c.submit "Submit Comment", class: "btn btn-tiny" %></p>
</div>
</div>
<% end %>
So the problem is when I am writing the CommentsController, I do not know how to pass the photo's id (photo_id) from the previous "show" page to the create method. Is it only possible if a pass it thru via a hidden field in the form? Are there any more elegant way in Rails to do so? Besides, a point on security, if I retrieve the photo_id via a hidden field, will someone be able to write a specific "post" request so that it post comments to all photos in the album? (like spammer in the php's forum long time ago..)
Thank you for reading this and thanks in advance for answering!
take a look at the rails guides on nested resources http://guides.rubyonrails.org/routing.html#nested-resources
your routes would have something like this.
resources :photos do
resources :comments
end
your photo controller would stay the same, but your comments controller would need to lookup the photo from the url
class CommentsController < ApplicationController
before_action :get_photo
def create
#photo.comments.create(params.require(:comment).permit(:comment_text))
....
end
...
def get_photo
#photo = Photo.find(params[:photo_id])
end
end
and the photo view would have
<%= form_for [#photo,Comment.new], html: {method: :post} do |c| %>
<div class="row">
<div class="span">
<%= image_tag current_user.avatar.url(:thumb) %>
</div>
<div class="span">
<p><%= c.label "Enter your comment here:" %></p>
<p><%= c.text_area :comment_text %></p>
<p><%= c.submit "Submit Comment", class: "btn btn-tiny" %></p>
</div>
</div>
<% end %>
which should invoke the new_photo_comment_path
as for the user_id i would just grabbed that from the user_signed_in helper. Since you already have them logged in, no sense in passing it in from the web.

Paperclip displaying multiple 'missing image' tags on edit page

So I have an object that has multiple photos (through use of a model called asset). I'm using paperclip to upload the photos and it's working fine. On my show page I call
<li class="grid_3">Photos:<br /></li>
<% #address.assets.each do |asset| %>
<li class='grid_3'><%= image_tag(asset.photo.url, size: '100x100') %></li>
<% end %>
and the photos display perfectly. when I click on the edit page:
<%= f.simple_fields_for :assets do |asset| %>
<%= render :partial => 'asset_fields', :locals => { :f => asset } %>
<% end %>
the partial is rendered:
<div class='nested-fields'>
<%= f.file_field :photo %>
<% unless f.object.new_record? %>
<%= f.file_field :photo %>
<% #address.assets.each do |asset| %>
<li class='grid_3'><%= image_tag(asset.photo.url, size: '100x100') %></li>
<% end %>
<% end %>
</div>
at this point the photos each show up 3 times along with an extra image tag with a 'missing' photo placeholder. I would say I've tried different things but I just don't see what is wrong with the code. Any ideas?
Assuming simple_fields_for behaves the same as fields_for... the call to f.simple_fields_for :assets is a loop already. It loops over f.object.assets and renders the contents of the block once for each item found using the asset form generator (it may be a little less confusing to call that block variable asset_form, by the way). So since you're then rendering a partial that also renders all of the assets for the #address that's why you get each image 3 times.

Rails Nested File Upload: Edit Content

I built an ajax upload form for image uploads with RoR which works well so far. The only problem I am facing is when editing content that has images attached to it. I want the images to show up as thumbnails (no problem) and below that a new upload field.
This is how I show the upload field normally in the view...
<%= form.fields_for :images do |builder|%>
<p><%= builder.label :image %></p>
<p id="ajax_upload"><%= builder.file_field :image %></p>
<% end %>
If I do this for editing content I get as many upload fields as images.. I just want one...
I generally do not refer to symbols for form builders, as they tend to behave in unexpected ways sometimes. You should be able to send in an object instance like so:
<% #image = #the_model.images.first %>
<%= form.fields_for #image do |builder|%>
<p><%= builder.label :image %></p>
<p id="ajax_upload"><%= builder.file_field :image %></p>
<% end %>

Resources