Parent model with nested polymorphic model image shrine (rails)

483 views
Skip to first unread message

candra wana

unread,
Jan 28, 2018, 7:47:35 AM1/28/18
to Shrine
Hi Janko,

I've parent model called Artwork that have many images as imageable (polymorphic). The detail the code:

artwork.rb
  has_many :images, as: :imageable, class_name: 'Image', dependent: :destroy

  accepts_nested_attributes_for :images, allow_destroy: true, reject_if: proc {
    |attributes| attributes['image'].blank? && attributes['id'].blank?
  }
  validates_associated :images

image.rb
class Image < ApplicationRecord
  include ImageUploader::Attachment.new(:image)
  belongs_to :imageable, polymorphic: true, optional: true

  validates_presence_of :image
end

image_uploader.rb
require "image_processing/mini_magick"

class ImageUploader < Shrine
  include ImageProcessing::MiniMagick

  plugin :determine_mime_type
  plugin :remove_attachment
  plugin :restore_cached_data
  plugin :store_dimensions
  plugin :validation_helpers
  plugin :processing
  plugin :versions

  Attacher.validate do
    validate_mime_type_inclusion ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
    validate_max_size 5.megabytes, message: 'Your image is too large (maximum is 5 MB)'
    validate_min_size 0.5.megabytes, message: 'Your image is too small (minimum is 0.5 MB)'
  end

  process(:store) do |io, context|
    { original: io,
      large: resize_to_limit!(io.download, 900, 900),
      medium: resize_to_limit!(io.download, 700, 700),
      small: resize_to_limit!(io.download, 500, 500)
    }
  end

  def generate_location(io, context)
    type = context[:record].class.name.downcase if context[:record]
    if context[:version] == :original
      style = "originals"
    elsif context[:version] == :large
      style = "larges"
    elsif context[:version] == :medium
      style = "mediums"
    elsif context[:version] == :small
      style = "smalls"
    end
    name = super

    [type, style, name].compact.join("/")
  end
end

When i create or update the artwork with image that have image size > 5MB or < 0.5MB the artwork seems to still update or save (not failed to save or update) and got an error because image_id is missing (this is because the image not saving by attacher validate).

The validation from attacher works because the image not creating at all, but my artwork keep doing save or update although the image failed to save or update.

Could you help me how to validate the size of image in parent model (artwork)?

Thanks


Hiren Mistry

unread,
Jan 28, 2018, 4:53:49 PM1/28/18
to Shrine
If I understand your problem correctly, the image validation is working correctly but you want the parent model to also fail if the image fails validation.

This is more of a Rails question then Shrine. Rails has an `validates_associated` validation that you can use. See this SO post: https://stackoverflow.com/questions/15916024/rails-3-fail-validation-for-parent-model-is-validation-of-nested-attributes-fail.

One thing I noticed in your code, here you are downloading `io` several times when you can download it once and use it from there without the destructive resizing. Recommend the following:
 process(:store) do |io, context|

    orig
= io.download
   
{ original: orig,
      large
: resize_to_limit(orig, 900, 900),
      medium
: resize_to_limit(orig, 700, 700),
      small
: resize_to_limit(orig, 500, 500)
   
}
 
end


Regards,
Hiren

candra wana

unread,
Jan 28, 2018, 10:23:26 PM1/28/18
to Shrine
Yes you're right, the parent model supposed to be fail if the image fails. I've tried using validates_associated :images before, but it doesn't works too.

Thanks for the correction recommendation in io store.

Hiren Mistry

unread,
Jan 29, 2018, 1:53:24 AM1/29/18
to Shrine

Here's a working test script. Shrine is working correctly with ActiveRecord. You may want to check things on the Rails side. However if you do find a bug in Shrine, please report back with a similar test script that reproduces the bug so we can investigate it.

require 'active_record'
require "shrine"
require "shrine/storage/file_system"
require "tmpdir"
require 'byebug'


Shrine.plugin :activerecord
Shrine.storages = {
  cache
: Shrine::Storage::FileSystem.new(Dir.tmpdir, prefix: "cache"),
  store
: Shrine::Storage::FileSystem.new(Dir.tmpdir, prefix: "store"),
}


class MyUploader < Shrine
 
# plugins and uploading logic
  plugin
:validation_helpers


 
Attacher.validate do
    validate_max_size
1*1024 # < test image size => album + image not created
   
# validate_max_size 10*1024  # > test image size => album + image created
 
end
end


ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Migration.verbose = false


ActiveRecord::Migration.create_table(:albums) do |t|
  t
.text :title
end


ActiveRecord::Migration.create_table(:images) do |t|
  t
.text :image_data
  t
.integer  "album_id"
end


class Album < ActiveRecord::Base
  has_many
:images
  accepts_nested_attributes_for
:images
end


class Image < ActiveRecord::Base
  belongs_to
:album
  include
MyUploader::Attachment.new(:image)
end


# your test image
file
= File.new("../test/fixtures/image.jpg")


# image = Image.create(image: open(file))
# puts image.inspect


album
= Album.create(title: "Bob", images_attributes: [{ image: open(file) }])
# byebug
puts album.inspect
puts album.images.inspect

puts Album.all.inspect
puts Image.all.inspect

# Results:

# Image > max size limit => Nothing created
#<Album id: nil, title: "Bob">
#<ActiveRecord::Associations::CollectionProxy [#<Image id: nil, image_data: "{\"id\":\"2734534a82836c81dabfde8f0ed7fced.jpg\",\"stor...", album_id: nil>]>
#<ActiveRecord::Relation []>
#<ActiveRecord::Relation []>

# Image < max size limit => Album + Image created
#<Album id: 1, title: "Bob">
#<ActiveRecord::Associations::CollectionProxy [#<Image id: 1, image_data: "{\"id\":\"01cc67392344ef36a85cdf7c79f79c05.jpg\",\"stor...", album_id: 1>]>
#<ActiveRecord::Relation [#<Album id: 1, title: "Bob">]>
#<ActiveRecord::Relation [#<Image id: 1, image_data: "{\"id\":\"01cc67392344ef36a85cdf7c79f79c05.jpg\",\"stor...", album_id: 1>]>


candra wana

unread,
Jan 29, 2018, 2:00:47 AM1/29/18
to Shrine
I’ve got an another error after updated io process

Sucker Punch job error for class: ‘PromoteJob’ args: […]
Shrine::Error detected multiple versions that point to the same IO object: given versions: [:original, :large, :medium, :small], unique versions: [:small]

candra wana

unread,
Jan 29, 2018, 2:07:20 AM1/29/18
to Shrine
But the the validation seems to works on parent model (with error message from attacher validate).

Hiren Mistry

unread,
Jan 29, 2018, 2:08:50 AM1/29/18
to Shrine
Try this more verbose version or it might just be replacing the `original: orig` with `original: io`.

process(:store) do |io, context|

    orig 
= io.download

    lg = resize_to_limit(orig, 900, 900)
    med = resize_to_limit(orig, 700, 700)
    sm = resize_to_limit(orig, 500, 500)

    
{ original: io,
      large
: lg,
      medium
: med,
      small
: sm
    
}
  
end

Hiren Mistry

unread,
Jan 29, 2018, 2:14:05 AM1/29/18
to Shrine
I don't follow... could you provide more context on what you're referring to and what you mean.

candra wana

unread,
Jan 29, 2018, 2:27:14 AM1/29/18
to Shrine
Sorry i’m still on outside, the first problem is when i’v create or update the parent model with failed image validate. The parents still do the action not failed (save or update) so the parents will routes to post but got an errr because no image id, the shrine works perfectly not uploaded the image.

But after i edited io process, i’ve got an error in background job & shrine, but the validation on parent model seems works, image failed to upload the parent failed to save or update and got an error message from attacher validate if the image not meet the requirements.

Thanks.

Hiren Mistry

unread,
Jan 29, 2018, 2:44:02 AM1/29/18
to Shrine


On Sunday, January 28, 2018 at 11:27:14 PM UTC-8, candra wana wrote:
Sorry i’m still on outside, the first problem is when i’v create or update the parent model with failed image validate. The parents still do the action not failed (save or update) so the parents will routes to post but got an errr because no image id, the shrine works perfectly not uploaded the image.


I've provided you with a test script showing that the parent model fails to create if the image model fails validation. Please look at that and compare with your code. If Shrine is working correctly, then you should ask Rails why your parent model still works when child model fails validation.

 
But after i edited io process, i’ve got an error in background job & shrine, but the validation on parent model seems works, image failed to upload the parent failed to save or update and got an error message from attacher validate if the image not meet the requirements.

Thanks.


Did you try the updated code sample I sent you 30 mins ago?

Janko Marohnić

unread,
Jan 29, 2018, 7:08:40 AM1/29/18
to Hiren Mistry, Shrine
I’ve got an another error after updated io process
Sucker Punch job error for class: ‘PromoteJob’ args: […]
Shrine::Error detected multiple versions that point to the same IO object: given versions: [:original, :large, :medium, :small], unique versions: [:small]

As the error message says, at least two of your versions are the exact same IO object (have the same object ID). This can happen if you're using in-place resizing (with a "!" at the end), so for example the following processing code would trigger that error:

process(:store) do |io, context|
  original = io.download
  thumb = resize_to_limit!(original, 500, 500) # modifies orignal in place, so now both `original` and `thumb` are the same IO object

  { original: original, thumb: thumb }
end

Kind regards,
Janko

--
You received this message because you are subscribed to the Google Groups "Shrine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ruby-shrine+unsubscribe@googlegroups.com.
To post to this group, send email to ruby-...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ruby-shrine/3c7996bd-f767-4933-84a7-d6fe4c798de3%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

candra wana

unread,
Jan 30, 2018, 12:41:11 PM1/30/18
to Shrine
Hi Janko & Hiren

Thank you in advance for the support & help, shrine works perfectly fine. The problem seems caused by cocoon for nested attributes, when the child (image) model not pass to validate, the existing image_id in parent model goes missing after render and then rise an error.

Sorry, my bad.

Thanks.


Pada Senin, 29 Januari 2018 19.08.40 UTC+7, Janko Marohnić menulis:
I’ve got an another error after updated io process
Sucker Punch job error for class: ‘PromoteJob’ args: […]
Shrine::Error detected multiple versions that point to the same IO object: given versions: [:original, :large, :medium, :small], unique versions: [:small]

As the error message says, at least two of your versions are the exact same IO object (have the same object ID). This can happen if you're using in-place resizing (with a "!" at the end), so for example the following processing code would trigger that error:

process(:store) do |io, context|
  original = io.download
  thumb = resize_to_limit!(original, 500, 500) # modifies orignal in place, so now both `original` and `thumb` are the same IO object

  { original: original, thumb: thumb }
end

Kind regards,
Janko
On Mon, Jan 29, 2018 at 8:44 AM, Hiren Mistry <hiren....@chai-monsters.com> wrote:


On Sunday, January 28, 2018 at 11:27:14 PM UTC-8, candra wana wrote:
Sorry i’m still on outside, the first problem is when i’v create or update the parent model with failed image validate. The parents still do the action not failed (save or update) so the parents will routes to post but got an errr because no image id, the shrine works perfectly not uploaded the image.


I've provided you with a test script showing that the parent model fails to create if the image model fails validation. Please look at that and compare with your code. If Shrine is working correctly, then you should ask Rails why your parent model still works when child model fails validation.

 
But after i edited io process, i’ve got an error in background job & shrine, but the validation on parent model seems works, image failed to upload the parent failed to save or update and got an error message from attacher validate if the image not meet the requirements.

Thanks.


Did you try the updated code sample I sent you 30 mins ago?

--
You received this message because you are subscribed to the Google Groups "Shrine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ruby-shrine...@googlegroups.com.

To post to this group, send email to ruby-...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages