My rails application has two models, gallery and photo. Galleries have many photos and photos belong to one gallery.
When I delete a photo, I noticed that rails also loads the gallery - which I do not need. It is an added database query.
When I find the photo to delete, I use #photo = Photo.find(params[:id]). This loads the association.
I know that there is #photo = Photo.find(params[:id], :include => :gallery), which tells it to load the gallery. What is the opposite of this? I tried the following:
#photo = Photo.find(params[:id], :include => [])
#photo = Photo.find(params[:id], :include => nil)
I also tried to select only the fields that I need in order to delete the photo, but I need the gallery_id in order to delete the actual file because the path of the file is based off the gallery. This just ends up loading the gallery too.
Edit:
My Photo model looks like this:
class Photo < ActiveRecord::Base
belongs_to :gallery
mount_uploader :file, PhotoUploader
end
mount_uploader is from carrierwave. I have an uploader with the following code in it:
def store_dir_base
"galleries/#{model.gallery.id}/"
end
Could it be the culprit?
Thanks!
The reason this was happening was because of my uploader code that I used for carrierwave.
This code was accessing the gallery model, when all I needed to access was the id:
def store_dir_base
"galleries/#{model.gallery.id}/"
end
All I had to do was change it to:
def store_dir_base
"galleries/#{model.gallery_id}/"
end
This made it so I was accessing the photo model column gallery_id instead of the gallery model.
Related
I am using rails_admin gem for the rails api application for the backend admin side.
I am using rails 6 with active_storage and storing attachments on the S3.
On the admin side, I need to display the list of attachments which might be images or files anything.
My question is How to show those in index method, do I need to show images then what to show in pdf/docs, do I need to show the only the link of s3?
currently, it looks like these broken images are the images and other one were files
My model
class Attachment < AttachmentBlock::ApplicationRecord
self.table_name = :attachments
include Wisper::Publisher
has_one_attached :attachment
belongs_to :account, class_name: 'AccountBlock::Account'
has_and_belongs_to_many :orders , class_name: 'BxBlockOrdermanagement::Order'
scope :not_expired, -> {where('is_expired = ?',false)}
end
What should I use here to list the attachment that the user upload?
how to check the attachment type and then if its image then shows the image and if it files then show file url from s3?
thanks.
Yours is a two part question:
To add links to the side menu on rails admin you need to define models so if you wanted an index for all the attachments of type 'pdf' you could use rails STI (single table inheritance) or define a custom default_scope like this:
class ImageAttachment < Attachment
def self.default_scope
where('attachments.attachment LIKE ?', '%png') }
end
end
To customize the row of each individual attachment record you need to defined that behavior for the field on the model rails admin config.
For example you can put this block of code inside your ImageAttachment class.
class ImageAttachment < Attachment
def self.default_scope
where('attachments.attachment LIKE ?', '%png') }
end
rails_admin do
configure :attachment do
view = bindings[:view]
attachment = bindings[:object]
if view
view.content_tag(:img, attachment.attachment.url)
else
''
end
end
list do
field :attachment
end
end
end
As you can see inside the attachment field configuration block you have access to the attachment object and of course all its methods, you can determine the type of attachment and do some special html rendering.
In the rails application I am developing, I want the to give the end users the ability to select an avatar. Nothing unusual here.
Unfortunately, I have found numerous articles, posts and gems about the uploading and selection of images (example: Is there any rails gem for avatar selection? | http://rubygems.org/gems/paperclip ) but what I want is for them to select from an 'Avatar' table in my database. I do not want them to be able to upload anything. The Avatars which they can select from will be created for them.
My thought is that the Avatar table would have two columns: id and url_path.
In their user profile I would have a field I assume to store the avatar_id -- but from there I am stuck --- I want them to see the gallery of avatars and make a selection to populate that field. I am open to a gem -- but most seem more complex than I need.
Any assistance would be appreciated.
Here's some input to push you in the right direction. I don't think you need a gem for this.
You need three models:
class User < ActiveRecord::Base
has_one :avatar, through: :profile_picture
has_one :profile_picture
# change both associations to has many if a user can have multiple avatars
end
class Avatar < ActiveRecord::Base
has_one :profile_picture
# attribute: filename
end
class ProfilePicture < ActiveRecord::Base
belongs_to :user
belongs_to :avatar
# attributes: user_id and avatar_id
end
The profile picture model links users with avatars.
Since the user will only be able to choose from a set of avatars, you simply create the avatars as admin. Just put avatar images in assets/images/avatars and create the avatar records in the database yourself:
# assuming an avatar's filename is avatar.png
Avatar.create(filename: 'avatar.png')
# and make sure you have such an image in assets/images/avatars
Then, assuming you have a page where you render all avatars as, e.g., linked images as preview that users can click on to select one, you could simply link those images to a ProfilePicturesController's create action. You will need the following route
resources :profile_pictures, only: [ :create ]
and the following erb code for your images for the user to choose from:
<% Avatar.all.each do |a| %>
<%= link_to image_tag("assets/images/avatars/#{a.filename}"), profile_pictures_path(avatar_id: a.id), method: :post %>
<% end %>
and the following controller code:
class ProfilePicturesController < ActionController::Base
def create
ProfilePicture.create(
avatar_id: params[:avatar_id],
user_id: current_user.id # or however you retrieve the current user
)
flash[:notice] = 'Avatar updated.' # just a suggestion
redirect_to :back # just a suggestion
end
end
Haven't actually tried any of this, so let me know if it works.
I have User model with the following association:
class User < ActiveRecord
has_many :pictures, :as => :imageable
accepts_nested_attributes :pictures
end
My Picture model looks like this:
class Picture < ActiveRecord
belongs_to :imageable, :polymorphic => true
has_attached_file :image
end
Now, I want to user to be able to upload maximum 5 images. And he will select 1 image as his avatar. Now, user can upload images but I don't know how to limit the maximum number of pictures. One more thing, user needs to be able to change his avatar image. How can I achieve this?
In my view, I use input file with name user[picture_attributes][0][image] in order to allow user to change the first picture but it keeps inserting new pictures into database instead of replacing the first picture.
Please help me on this.
Thanks in advance
For the first part of the problem you have, i would suggest you use rails built-in counter_cache method.
Your picture model would thus become:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true, counter_cache: true
has_attached_file :image
end
Also you would need to add a column called pictures_count to the User model.
This way in your controller you could check if the count is upto 5 records and therefore inform them that they have uploaded the maximum allowed.
if #user.pictures.size == 5 #sorry no more uploads
For the second part of the problem. Is the form action pointed to the new/create action or to your update action. If pointed to the new action a new record would be created but if pointed to the update action then it should change the first image record as you expect.
#charinten For the second part of the problem, some suggestions:
You could try making the id of the pictures accessible in the user model. This way when you try to point to the image to use as an avatar, rails uses that id to update the record. If you try to update the record without pointing rails to that id, it would assume you are trying to create a new record.
Also rather than using user[picture_attributes][0][image] you could in your user profile. Find a specific image and point to that image on the edit action.
Hope this helps
How can i authentically use rails relationships in my case?
I'm making a nightlife website, just for you to know the context. It has three models, i want to join on one page: Places, Albums, Photos.
So, photos in albums work great, i use there a custom-coded sql with joins.
But when i click on a place i want to see info from place model and a list of albums with a sample photo (first for example)
Now i have the following:
class Place < ActiveRecord::Base
has_many :albums
end
class Album < ActiveRecord::Base
has_many :photos
has_one :place
end
class Photo < ActiveRecord::Base
belongs_to :album
end
And there how i get it in my controller:
#place = Place.find( params[:id], :include => :albums )
and i get #place.albums as an object with albums data. But i dont know how to dig even deeper to reach thephotosmodel. And anywhay i can:include => :albumsbecause i have no direct relations betweenplaceandalbum, but i have them inalbum > photo` so sql join is needed?
That's a complicated question, but i just don`t get it fully.
Thank you for any help, maybe a good link to read!
First of all, the association between Place and Album isn't correct. The way you have it setup, it looks like neither would have a foreign_key. In other words, it should be Album belongs_to :place, with place_id in the albums table.
Second of all, to get the first photo for each album:
<% #place.albums.each do |album| %>
Sample Photo: <%= image_tag(album.photos.first.url) %>
<% end %>
If you really wanted to, you could get the first photo from the first album of a place in one line:
<%= image_tag(#place.albums.first.photos.first.url) %>
First note that this is prone to nil errors if you don't add in conditionals, so I don't actually recommend this method. But, if you were to use it, I would just add a method to the Place model:
def first_photo
albums.first.photos.first
end
And in your view:
<%= image_tag(#place.first_photo.url) %>
You'll want to join this stuff together as well so you're not performing too many queries. Wizard of Ogz answer covers that.
There is a hash syntax for nested includes. It also works for joins.
#place = Place.find( params[:id], :include => {:albums => :photos} )
Here is the documentation for this http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Look under the heading "Eager loading of associations"
I've created:
PhotoAlbum (id, name)
has_many: photos
Photo (id, name, photo_album_id)
belongs_to: photo_album
I want to allow a user to upload 1 or more photos. Per Upload whether it be 1 or more photos, they should automatically be added to a new album.
So the way i have it is, a user clicks upload photos:
They get the photo view where they get the form. They can then upload 1 photo (in the future I want to support more than 1, but baby steps!
so now in my Photos Controller, I have DEF CREATE
Q: How in the DEF CREATE, do I auto create an album and then create the photos? Something like?
#photo_album = PhotoAlbum.create
#photo = #photo_album.create(params[:photo])
? Is this the right Rails way to do this?
Thanks
#photo_album = PhotoAlbum.create({:name => "My Photo Album"})
#photo = #photo_album.photos.build({:name => params[:photo]})
I'm assuming your params[:photo] is the name, but you get the idea.