Sean C. wrote:
Wow. That’s very little code.
I love Rails.
Absolutely
Anyway, I know this is the kind of question that probably everybody
hates, but if anyone has the patience, could you break down a few points
in this technique for the non-programmer?
For example, this notation:
def image=(file)
I’d understand “def image(file)”, where image would be the function name
and file would be the parameter, but I’ve never seen an equals sign used
that way before. What does it do?
adding an equals sign just makes an equal sign part of the method name.
You can also have ? and ! in your method names. What this does is when
you say:
SomeModel.image = params[:some_model][:image]
It will call the image= method with the argument of
params[:some_model][:image]. Ruby does not interpret the above code as
an assignment, but rather simply a method call. The reason this works
with:
SomeModel.create(params[:some_model])
Is that rails internally takes every attribute the hash that you provide
to the create method and calls the “=” method for it. So when you
write:
SomeModel.create({:foo => ‘bar’, :baz => ‘123’})
Rails internally executes:
model = SomeModel.new
model.foo = ‘bar’
model.baz = ‘123’
model.save
So when we define an “attribute=(value)” method it allows to wrap some
other processing around a simple assignment, such as saving an uploaded
image to the disk.
And as a minor note this magic also works with [] and []=
class Foo
def
“Passed in #{key.to_s.upcase}”
end
def []=(key, value)
“You tried to make the key #{key} the value of #{value}”
end
end
foo = Foo.new
foo[:doodle] #=> “Passed in Doodle”
foo[:gnarf] = ‘foo’ #=> “You tried to make the key gnarf the value of
foo”
and this:
File.open("#{RAILS_ROOT}/public/images/#{file.original_filename}",
“w+”) do |f|
f.write file.read
is “original_filename” real code or pseudocode?
Totally real code. Look in to “Multipart Requests” section of the CGI
class documentation here: http://www.ruby-doc.org/core/classes/CGI.html
Uploaded files have a few extra methods, namely: orginal_filename,
local_path, and content_type
Although, you only need to use that if you care about the original
filename. If you are mapping them directly to a model you may want to
simply name the file with the id of the record it belongs to instead.
But this:
def upload
Avatar.create(params[:avatar])
end
this means that I would need an “Avatar” model, right? And the file
would just be stored in the images folder and no database activity would
take place?
Yes.
Or if you want it to write to a binary database field:
def image=(file)
self[:image] = file.read
end
the [] notation allows to read and write the attributes of your model if
you have ovveridden the normal accessor methods like we did here. And
the read method simply pulls all the data out of the file object as a
string, a big string.
However, this entire methodology was assuming you wanted to store an
image that directly relates to a record. If you just want to upload
random images to a folder in your web root, meaning without any model at
all, then its super easy.
Create a new file and write into it what you read out of the uploaded
file. This is a snippet from one of my apps:
#view
<%= file_field_tag ‘file’ %>
#controller
def upload
File.open
“#{RAILS_ROOT}/public/misc/#{params[:file].original_filename}”, ‘wb’ do
|f|
f.write(params[:file].read)
end
redirect_to :action => ‘index’
end