I've got a class which loads files and turns them into ActiveRecord DB
rows. I'm converting images on a filesystem into blobs in a database.
class ImageFile < ActiveRecord::Base
class << self
def import_from_hash(hash)
%w{medium square thumb lsquare lthumb tiny}.each do |suffix|
filename = "public/item/photos/" + hash[0..2] + "/" + hash +
"_#{suffix}.jpg"
if File.exists?(filename)
File.open(filename, "r") do |file|
image_file = ImageFile.new
eval ("image_file.#{suffix} = file.read")
end
end
end
end
end
end
As you can see the whole thing depends massively on eval(). Yet I
think it's safe. First, it's only supposed to be run from irb. Second,
the eval's guarded by an array which essentially acts as a filter. It
only ever evals code generated by this code and literals from the
array. (No user input.)
The suffixes match existing suffixes on the filesystem. They
correspond to different sizes of the same image. I'm essentially
refactoring an architecture here. That's why the redundant data in the
DB. Each image now being represented on the filesystem with
"xyz_square.jpg" will soon become the square attribute of an ImageFile
object. This isn't the cleanest design, but it beats the filesystem
version for my purposes (load-balance-ability and hardware stability).
Anyway, I think in addition to being safe, this code also shows
something which would end up **significantly** less concise without
eval(). It's kind of deliberately Lispy and functional-programmy. I
would never have written anything like this before reading
"Higher-Order Perl." I think it's a good example of eval() being
useful and safe. But, you know, please knock me down (if you see me
getting high and mighty).
Anyway, I think in addition to being safe, this code also shows
something which would end up **significantly** less concise without
eval().
Hmm I dislike eval very strongly, therefore:
not tested but I think
image_file.send "#{suffix}=", file.read
or even (it it is an accessor)
image_file.instance_variable_set, "@" << suffix, file.read
should work too
It's kind of deliberately Lispy and functional-programmy. I
would never have written anything like this before reading
"Higher-Order Perl." I think it's a good example of eval() being
useful and safe. But, you know, please knock me down (if you see me
getting high and mighty).
On 7/17/07, Giles Bowkett <gilesb@gmail.com> wrote:
--
I always knew that one day Smalltalk would replace Java.
I just didn't know it would be called Ruby
-- Kent Beck
I've got a class which loads files and turns them into ActiveRecord DB
rows. I'm converting images on a filesystem into blobs in a database.
class ImageFile < ActiveRecord::Base
class << self
def import_from_hash(hash)
%w{medium square thumb lsquare lthumb tiny}.each do |suffix|
filename = "public/item/photos/" + hash[0..2] + "/" + hash +
"_#{suffix}.jpg"
if File.exists?(filename)
File.open(filename, "r") do |file|
image_file = ImageFile.new
eval ("image_file.#{suffix} = file.read")
end
end
end
end
end
end
As you can see the whole thing depends massively on eval(). Yet I
think it's safe.
--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars
I've got a class which loads files and turns them into ActiveRecord DB
rows. I'm converting images on a filesystem into blobs in a database.
class ImageFile < ActiveRecord::Base
class << self
def import_from_hash(hash)
%w{medium square thumb lsquare lthumb tiny}.each do |suffix|
filename = "public/item/photos/" + hash[0..2] + "/" + hash +
"_#{suffix}.jpg"
if File.exists?(filename)
File.open(filename, "r") do |file|
image_file = ImageFile.new
eval ("image_file.#{suffix} = file.read")
end
end
end
end
end
end
As you can see the whole thing depends massively on eval(). Yet I
think it's safe. First, it's only supposed to be run from irb. Second,
the eval's guarded by an array which essentially acts as a filter. It
only ever evals code generated by this code and literals from the
array. (No user input.)
The suffixes match existing suffixes on the filesystem. They
correspond to different sizes of the same image. I'm essentially
refactoring an architecture here. That's why the redundant data in the
DB. Each image now being represented on the filesystem with
"xyz_square.jpg" will soon become the square attribute of an ImageFile
object. This isn't the cleanest design, but it beats the filesystem
version for my purposes (load-balance-ability and hardware stability).
Anyway, I think in addition to being safe, this code also shows
something which would end up **significantly** less concise without
eval(). It's kind of deliberately Lispy and functional-programmy. I
would never have written anything like this before reading
"Higher-Order Perl." I think it's a good example of eval() being
useful and safe. But, you know, please knock me down (if you see me
getting high and mighty).
ActiveRecord has the write_attribute and read_attribute methods
which is a better choice for what you are doing. You can also
use and = as aliases for write_attribute and read_attribute
Suffixes = %w{medium square thumb lsquare lthumb tiny}
class ImageFile < ActiveRecord::Base
def ImageFile.import_from_hash(hash)
Suffixes.each do |suffix|
filename =
"public/item/photos/" + hash[0..2] + "/" + hash + "_#{suffix}.jpg"
if File.exists?(filename)
File.open(filename, "r") do |file|
image_file = ImageFile.new
self[suffix]=file.read
end
end
end
end
end
As you can see the whole thing depends massively on eval().
I see you've already got the answers on eval(), which I completely agree with.
Each image now being represented on the filesystem with
"xyz_square.jpg" will soon become the square attribute of an ImageFile
object. This isn't the cleanest design, but it beats the filesystem
version for my purposes (load-balance-ability and hardware stability).
My database teacher use to harp on and on about how file data belonged in the file system (not a database). His primary reasoning was that you can't meaningfully query it so you don't gain anything from the database structure. I've also found that things get complicated as soon as I have a large enough file stored in a database.
Just my two cents.
James Edward Gray II
···
On Jul 17, 2007, at 12:51 AM, Giles Bowkett wrote:
Hrm, sorry, no. Too tired to notice no #{} around file.read.
Still, far too dangerous, use #send instead.
···
On Jul 17, 2007, at 01:18, Eric Hodel wrote:
On Jul 16, 2007, at 22:51, Giles Bowkett wrote:
I've got a class which loads files and turns them into ActiveRecord DB
rows. I'm converting images on a filesystem into blobs in a database.
class ImageFile < ActiveRecord::Base
class << self
def import_from_hash(hash)
%w{medium square thumb lsquare lthumb tiny}.each do |suffix|
filename = "public/item/photos/" + hash[0..2] + "/" + hash +
"_#{suffix}.jpg"
if File.exists?(filename)
File.open(filename, "r") do |file|
image_file = ImageFile.new
eval ("image_file.#{suffix} = file.read")
end
end
end
end
end
end
As you can see the whole thing depends massively on eval(). Yet I
think it's safe.
Agreed, but you can't tell from his code sample that he's not doing that already. We've got a similar model class (tree of classes actually) whose @content doesn't go the db but gets saved in a after_save handler instead. He might just be storing the useful stuff in the db (dimensions, size, mimetype, and just having a row so tagging and other referential things can happen).
···
On Jul 17, 2007, at 06:42 , James Edward Gray II wrote:
My database teacher use to harp on and on about how file data belonged in the file system (not a database). His primary reasoning was that you can't meaningfully query it so you don't gain anything from the database structure. I've also found that things get complicated as soon as I have a large enough file stored in a database.
ActiveRecord has the write_attribute and read_attribute methods
which is a better choice for what you are doing. You can also
use and = as aliases for write_attribute and read_attribute
It's a class method which creates new instances. I don't think you can
get to write_attribute that way, because it's a private method.
> Each image now being represented on the filesystem with
> "xyz_square.jpg" will soon become the square attribute of an ImageFile
> object. This isn't the cleanest design, but it beats the filesystem
> version for my purposes (load-balance-ability and hardware stability).
My database teacher use to harp on and on about how file data
belonged in the file system (not a database). His primary reasoning
was that you can't meaningfully query it so you don't gain anything
from the database structure. I've also found that things get
complicated as soon as I have a large enough file stored in a database.
I have to admit, storing the images in the DB is kind of a lame hack.
We're doing it because we need to be able to load-balance the app
across three servers, and storing images on the filesystem the way the
app currently does it blocks the load-balancing. It could probably be
done more correctly if we had a dedicated image server, but there are
budget questions there.
I made my assumption about how he was doing it from his comment, "I'm converting images on a filesystem into blobs in a database."
James Edward Gray II
···
On Jul 17, 2007, at 10:42 AM, Ryan Davis wrote:
On Jul 17, 2007, at 06:42 , James Edward Gray II wrote:
My database teacher use to harp on and on about how file data belonged in the file system (not a database). His primary reasoning was that you can't meaningfully query it so you don't gain anything from the database structure. I've also found that things get complicated as soon as I have a large enough file stored in a database.
Agreed, but you can't tell from his code sample that he's not doing that already. We've got a similar model class (tree of classes actually) whose @content doesn't go the db but gets saved in a after_save handler instead. He might just be storing the useful stuff in the db (dimensions, size, mimetype, and just having a row so tagging and other referential things can happen).
Agreed, but you can't tell from his code sample that he's not doing
that already. We've got a similar model class (tree of classes
actually) whose @content doesn't go the db but gets saved in a
after_save handler instead. He might just be storing the useful stuff
in the db (dimensions, size, mimetype, and just having a row so
tagging and other referential things can happen).
I have to admit, storing the images in the DB is kind of a lame hack.
We're doing it because we need to be able to load-balance the app
across three servers, and storing images on the filesystem the way the
app currently does it blocks the load-balancing. It could probably be
done more correctly if we had a dedicated image server, but there are
budget questions there.
ActiveRecord has the write_attribute and read_attribute methods
which is a better choice for what you are doing. You can also
use and = as aliases for write_attribute and read_attribute
It's a class method which creates new instances. I don't think you can
get to write_attribute that way, because it's a private method.
Not a problem! Just use use and = public aliases for the protected methods.
Returns the value of the attribute identified by attr_name after it has been typecast (for example, "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). (Alias for the protected read_attribute method).
[ show source ]
# File lib/active_record/base.rb, line 1489
1489: def (attr_name)
1490: read_attribute(attr_name)
1491: end
=(attr_name, value)
Updates the attribute identified by attr_name with the specified value. (Alias for the protected write_attribute method).
[ show source ]
# File lib/active_record/base.rb, line 1495
1495: def =(attr_name, value)
1496: write_attribute(attr_name, value)
1497: end