RoR not creating nested record on before_save - ruby-on-rails

I have a model Site which has_many photos.
In site model I have
before_save :defaults
def defaults
if self.photos.length ==0 && !SiteDefault.default_photo.nil?
photo = Photo.new
photo.image = SiteDefault.default_photo.image
self.photos.push photo
end
end
It is not storing the default photo when creating a site. Why?
I dont see any error in the console. The image is being uploaded to Amazon S3 correctly.

Related

How to get the image url after callback in ActiveStorage

I have a model named Food where i have used active storage to save the image of food.
I have set a after_create callback where i want to get the image url. To do this i have done
class Food < ApplicationRecord
has_one_attached :image
after_create :check_image_url
private
def check_image_url
url = url_for self.image
end
end
But this gives me a error
undefined method `url_for' for #<Food:0x00007f6b4cd7c440>
Is there anyway i can achieve this?

Why are Active Record callbacks bypassed on associated records?

I'm building a web application with Rails 5 and have run into an issue updating associated records through a parent record when I have defined non-persistent attributes (with attr_accessor) on the associated records. Specifically, I have the user supply the non-persistent attributes on the child records in some way, and, based on the values of those attributes, assign values to persistent attributes in a before_save callback. The problem is that the child records are not saved to the database (and hence the save callback is not called) unless persistent attributes are changed on the child records through the parent.
I've run into this issue in several different situations, but the (simplified) example here deals with using the Paperclip Gem to process images uploaded to AWS S3 by a client browser.
app/models/dog.rb
class Dog < ApplicationRecord
has_many :certificates, :dependent => :destroy
accepts_nested_attributes_for :certificates, :allow_destroy => true
end
app/models/certificate.rb
class Certificate < ApplicationRecord
# load with path to client-uploaded file on S3 and save to
# update digitized_proof attachment
attr_accessor :s3_key
belongs_to :dog
has_attached_file :digitized_proof,
:content_type => { :content_type => ['image/jpg', 'image/png'] }
before_save :fetch_digitized_proof_from_s3
def fetch_digitized_proof_from_s3
return unless self.s3_key.present?
# note `S3_BUCKET` is set in the aws initializer
s3_obj = S3_BUCKET.object(self.s3_key)
# load paperclip attachment via S3 presigned URL
s3_presigned_url = s3_obj.presigned_url(:get,
:expires_in => 10.minutes.to_i)
self.digitized_proof = URI.parse(s3_presigned_url)
end
end
apps/controllers/dogs_controller.rb excerpt
def update
#dog = Dog.find(params[:id])
if #dog.update(dog_params)
redirect_to ...
...
end
private
def dog_params
params.require(:dog).permit(
...,
:certificates_attributes => [:id, :_destroy, :s3_key]
)
end
I've written javascript that uploads images to a temporary folder in an S3 bucket directly from the client's browser and adds the s3_key to the update form so the image can be identified and processed server-side (see the fetch_digitized_proof_from_s3 method in certificate.rb). The issue is that the certificates are never updated unless an actual database attribute has changed in the update parameters.
Why is this occurring and how can I work around it?
Sample parameters
{
...,
certificates_attributes: [
{id: '1', _destroy: '0', s3_key: 'tmp/uploads/certificates/.../photo.jpg'},
{id: '2', _destroy: '0', s3_key: 'tmp/uploads/certificates/.../photo2.jpg'}
]
}
Gem Versions
rails-5.0.0
activerecord-5.0.0
paperclip-5.1.0
aws-sdk-2.10.0
EDIT
I'm able to accomplish the update on the certificates by calling fetch_digitized_proof_from_s3 from within the setter method for s3_key (and removing the before_save callback):
# app/models/certificate.rb
def s3_key=(key)
#s3_key = key
self.fetch_digitized_proof_from_s3
end
This triggers the associated certificates to save properly (I'm thinking this occurs since digitized_proof, which is a persistent attribute, is updated by the call to fetch_digitized_proof_from_s3). This works, but I'd still rather fetch the image from S3 when the record is saved.
It appears the associated records will not update unless a change is registered with ActiveModel::Dirty. This does not occur when non-persisted attributes are set:
cert = Certificate.find(1)
cert.s3_key = 'tmp/uploads/certificates/...'
cert.changed? # => false
Adding the following method to Certificate.rb produces the desired behavior:
def s3_key=(key)
attribute_will_change!('s3_key') unless s3_key == key
#s3_key = key
end
Now the result is
cert = Certificate.find(1)
cert.s3_key = 'tmp/uploads/certificates/...'
cert.changed? # => true
and the associated records update appropriately when s3_key is set.

Paperclip add image from URL in has_many association

I've this models:
Prodcuts -> Products_Images.
I can add multiple images from a form uploading the image that it's my computer. I want to add images from URLs instead of locally images.
Paperclip has added this feature:
https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
but I don't know how to apply it in a has_many association.
I've tried adding a method in ProductImages model and call it for each URL after product is created. I don't know if I must use this method directly in Product model.
Where should I try to put the method of the wiki of Paperclip?
Here is a great gist (that I did not write). It should get you there: https://gist.github.com/jgv/1502777
require 'open-uri'
class Photo < ActiveRecord::Base
has_attached_file :image # etc...
before_validation :download_remote_image, :if => :image_url_provided?
validates_presence_of :image_remote_url, :if => :image_url_provided?, :message => 'is invalid or inaccessible'
private
def image_url_provided?
!self.image_url.blank?
end
def download_remote_image
io = open(URI.parse(image_url))
self.original_filename = io.base_uri.path.split('/').last
self.image = io
self.image_remote_url = image_url
rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
end
All credit to the author.
In the future, it's usually best to post the code with your attempt to solve the problem.

File downloaded from url with Carrierwave but "nil" field in my model

I'm integrating a video section in my small CMS.
I create a new video, I put the url in a form input field and then I must save the video url and also a thumbnail. Uusually videos are from Vimeo and Youtube.
I'm using CarrierWave to download thumb from url.
My Video model is this (simplified)
class Video < ActiveRecord::Base
mount_uploader :thumb_url, VideoThumbUploader
before_save :save_thumb_url
private
def save_thumb_url
self.remote_thumb_url_url = extract_thumb
end
def extract_thumb
thumb_url = if is_youtube_video?
youtube_thumb_url
elsif is_vimeo_video?
vimeo_thumb_url
else
'http://placehold.it/100x100'
end
end
end
In my folder I have the downloaded thumbnail, but the thumb_url column of my db is empty: when I save my form _thumb_url is NIL.
Why?
https://github.com/carrierwaveuploader/carrierwave/issues/1078
It's an issue. Here the workaround!

Rails 3 Dragonfly uid of attachment is correct but the file iself is nil

Im using Dragonfly and Amazon s3 for the image uploads. For some reason when I upload a picture, it saves to the right folder on amazon, and the uid is the right path, but it is not showing up!
Every time I call user.avatar it is nil even though user.avatar_uid is correct. How can I get the image to display properly with user.avatar.remote_url?
class User < ActiveRecord::Base
image_accessor :avatar do
storage_path { |file|
"#{self[:id]}/avatar/pic#{rand(1000)}.#{file.format.to_s.downcase}"
}
after_assign { |a|
self.avatar = a.jpg.thumb('300x300#n') if (VALID_PHOTO_TYPES.include? self.avatar.format)
}
end
attr_accessible :avatar_url, :retained_avatar, :avatar
attr_reader :id, :avatar_uid
The problem is the :avatar_uid in any of attr_reader, attr_writer, attr_accessible.
If you have that in your model, it will break. Pretend that the *_uid does not exist for any model with Dragonfly and only use user.avatar.

Resources