简体   繁体   中英

Ruby on Rails - passing a returned value of a method to has_attached_file. Do I get Ruby syntax wrong?

I'm writing my first RoR app and currently I'm working on allowing users to upload images. I'm using Paperclip for this purpose. One of the steps involves adding has_attached_file to my model:

class MyModel < ActiveRecord::Base
  #...
  has_attached_file :picture, styles: {
    large: "120x150#>", 
    small: "60x75#>"
  }
  #...
end

If I do it like this, everything works smoothly (or so it seems). But I will also need to access the same constant values as integers somewhere else, so I've added a hash:

class MyModel < ActiveRecord::Base
  #...
  has_attached_file :picture, styles: {
    large: "120x150#>", 
    small: "60x75#>"
  }
  def picture_sizes
  {
    large: {width: 120, height: 150},
    small: {width: 60, height: 75}
  }
  end
  #...
end

This creates an ugly redundancy. So I thought about writing a method generating the first hash from the second one, like this

class MyModel < ActiveRecord::Base
  #...
  has_attached_file :picture, styles: picture_sizes_as_strings

  def picture_sizes
  {
    large: {width: 120, height: 150},
    small: {width: 60, height: 75}
  }
  end

  def picture_sizes_as_strings
    result = {}
    picture_sizes.each do |label, size|
      result[:label] = "#{size[:width]}x#{size[:height]}#>"
    end
    return result
  end
  #...
end

But this rises an error:

undefined local variable or method `picture_sizes_as_strings' for #<Class:0x007fdf504d3870>

What am I doing wrong?

the has_attached_file is evaluated at Runtime. You've defined an instance method, but you aren't calling the method from an instance context.

Try:

def self.picture_sizes_as_strings
  # code here
end

Make sure you define the other method with self. also

and then:

has_attached_file :picture, :styles => picture_sizes_as_strings

should work.

The problem is that you're trying to use an instance method picture_sizes_as_strings in a declaration ( has_attached_image ) that's run on the class level. It's the difference between calling

MyModel.picture_sizes_as_strings

and

MyModel.first.picture_sizes_as_strings

In the first case we are referring to a class method (a method on the class MyModel itself) and in the second case we are referring to an instance method (a method on the individual my_model object.)

So first of all you have to change the methods to class methods by prefixing their names with self. , so:

def self.picture_sizes
  {
    large: {width: 120, height: 150},
    small: {width: 60, height: 75}
  }
end

Now that doesn't completely fix your problem yet, because has_attached_image is processed when the model is first parsed by ruby. That means it will try to run has_attached_image before you define self.picture_sizes so it will still say undefined method .

You can fix this by putting self.picture_sizes before the has_attached_file declaration but that's quite ugly. You could also put the data in a constant but that has its own problems.

Honestly there's no really pretty way to fix this. If it were me I'd probably reverse the whole process, define the styles as normal and then use a method to convert the strings to integers, something like this:

class MyModel < ActiveRecord::Base
  has_attached_file :picture, styles: {
    large: "120x150#>", 
    small: "60x75#>"
  }

  def numeric_sizes style
    # First find the requested style from Paperclip::Attachment
    style = self.picture.styles.detect { |s| s.first == style.to_sym }

    # You can consolidate the following into one line, I will split them for ease of reading
    # First strip all superfluous characters, we just need the numerics and the 'x' to split them
    sizes = style.geometry.gsub(/[^0-9x]/,'')
    # Next split the two numbers across the 'x'
    sizes = sizes.split('x')
    # Finally convert them to actual integer numbers
    sizes = sizes.map(&:to_i)
  end
end

Then you can call MyModel.first.numeric_sizes(:medium) to find out the sizes for a specific style, returned as an array. Of course you could change them into a hash too or whatever format you need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM