Rails user-conditional statement in model - ruby-on-rails

I'm working on a Rails app using attachment_ fu and Amazon S3 storage. Is it possible to make the :s3_ access (a part of the has_attachment options) conditional based on a user input when creating the object. I would like the user to be able if to select if the attachment is authenticated-read or public-read. Is this possible and how would you setup the conditional statement?
My model looks like this:
has_attachment :content_type => :image,
:storage => :s3,
:size => 0.kilobytes..6144.kilobytes,
:processor => 'Rmagick',
:resize_to => '650x500>',
:thumbnails => { :thumb => '75x75!' },
:s3_access => ( [[conditional]] ? 'authenticated-read' : 'public-read' )
Obviously [[conditional]] is what I'm looking to replace, but I don't know how to correctly setup a conditional for the item based off user action in the model. Maybe this is the wrong time of conditional for this type statement. Any suggestions?

James, I've done this before. I was digging through my old code, trying to find a sample I could show here, but I can't seem to find it. Old client, code is probably gone, etc...
You are on the right track though. Remember, 'has_attachment' is just a method call with a hash for the parameters, so if you treat it as such, you can adjust which hash values are ultimately sent to the method.
Edit - Here is a code sample -
production = ENV['RAILS_ENV'] == 'production'
has_attachment :content_type => :image,
:max_size => 1.megabyte,
:resize_to => '800x600>',
:thumbnails => { :thumb => '146x146>', :small => '75x75' },
# skip s3 for local development and testing
:storage => (production ? :s3 : :file_system),
:path_prefix => (production ? 'comment_images' : 'public/comment_images')
In the above example, I wanted to store uploads locally while developing, but switch to S3 when in production. So you are very close to where you need to be...

Related

How does lambda function works in rails with an example from paperclip gem

I had a problem with the Paperclip gem where the default_url doesn't load after it fingerprinted in production environment, my code was like this:
class User
# Attachments to Paperclip - Profile pic
has_attached_file :profilepic_attachment,
:styles => {
thumb: '100x100#',
square: '500x500#'
},
:default_url => ActionController::Base.helpers.asset_path("missing/default_user.png"),
:preserve_files => true
validates_attachment_content_type :profilepic_attachment, content_type: /\Aimage\/.*\Z/
end
Note that when I do rails c in production and print out ActionController::Base.helpers.asset_path("missing/default_user.png"). The fingerprinted version (correct version) is printed out.
default_user-fb34158daae99f297ad672c43bb1a4d3917d8e272b5f2254aa055392aa2faa94.png.
However, when I inspect it from browser, the original /assets/missing/default_user.png appeared.
I struggled for long time until I came across this post, which tells me to change
:default_url => ActionController::Base.helpers.asset_path("missing/default_user.png"),
to
:default_url => lambda { |image| ActionController::Base.helpers.asset_path("missing/default_user.png") },
I wasn't sure what happened, but then it works. I then wonder what lambda function is for and when is it used in rails? also, it passed in a variable |image| but seems it wasn't use in the code. Why is that?
Thanks!

Paperclip attachment saving with incorrect S3 URL about 50% of the time

Update:
So this is definitely related to the :hash_data option, specifically the :updated_at segment. Somehow the files are being saved to the S3 bucket with a different :updated_at value than Paperclip uses to read the file. Could this be due to some race condition, considering that it occurs intermittently? As I mentioned below, this issue began after upgrading Paperclip to 4.2.1.
I will greatly appreciate any thoughts/tips you guys have on this. Thank you!
When uploading images via Paperclip to S3 bucket, it sometimes saves the files with a different filename than that returned by the attachment#url method. For example, an image is saved to
main_event_photos_46_47fd4f3c2fea17fbb7a0bd27c648911557f9e12b_main.png
However calling #event.main_event_photo.url(:main) returns
main_event_photos_46_15744de74a36207b672356b5ad4c6b30eb4ba85f_main.png
So as you can see, the :hash section of the interpolation does not match, and I have no way of finding the actual url besides opening the bucket in the S3 console. This issue seems to occur about half the time. Sometimes uploading the exact same file does save properly, and the url method accesses it correctly.
This issue began occurring after we upgraded Rails/Ruby/Paperclip. We're now using:
Ruby 2.1.5
Rails 4.2.0
Paperclip 4.2.1
Note that on development, files always save correctly (local filesystem). I have scoured Stackoverflow and Google to no avail. Please let me know if I can provide any additional information. Thank you!
EDIT:
Model:
has_attached_file :main_event_photo, {
:styles => { :original => {:geometry => "1280x800#", :format => 'png'},
:main => {:geometry => "640x400#", :format => 'png'},
:thumb => {:geometry => "330x220#", :format => 'png'}
},
:convert_options => {:original => '-quality 80',
:main => '-quality 80',
:thumb => '-quality 80'
},
:default_style => :main
}.merge!(PAPERCLIP_STORAGE_OPTIONS) # this is defined in the config/environments
validates_attachment_content_type :main_event_photo, :content_type => ['image/jpeg', 'image/png', 'image/gif', 'image/x-png', 'image/pjpeg']
validates_attachment_presence :main_event_photo
Form (basically):
<%= simple_form_for(#event, :url => { :action => #event.id.nil? ? "create" : "update" }) do |f| %>
<%= f.file_field :main_event_photo %>
<% end %>
Note we have many models with Paperclip attachments, and the issue occurs on each.
So this turned out to be the result of a bug. I upgraded Rails to 4.2.1.rc1 which was released last week, and the issue was resolved. If anyone wants more information, check out the thread on Github: https://github.com/thoughtbot/paperclip/issues/1772. It includes a workaround for those who can't upgrade Rails.

Rails, PaperClip, S3, Heroku: Model icon fields not being saved

I am using Rails 3.2 + Heroku + S3 + Paperclip to store an icon on my User model. The model is not saving the 4 icon fields though. The images are getting processed and saved on S3 correctly and no errors are occurring. I also have another model that has a document being stored via Paperclip and S3. That model works perfectly in all cases. The User icon works locally but not on Heroku.
production.rb relevant configuration
config.paperclip_defaults = {
:storage => :s3,
:s3_credentials => {
:bucket => ENV['AWS_BUCKET'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
}
}
User model code:
class User < ActiveRecord::Base
attr_accessible :icon
has_attached_file :icon, :url => "/system/:rails_env/:attachment/:style/:hash.:extension",
:hash_data => ":class/:attachment/:id",
:hash_secret => "superSecretThing",
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:default_url => "/blank.png"
...
Controller code: (This code is kind of crazy because I am AJAXing files Base64 encoded.)
params[:user][:icon_data]
decoded_file = Base64.decode64(data)
begin
split_name = params[:user][:icon_file_name].split(".")
file = Tempfile.new([split_name[0..-2].join("."), ".#{split_name[-1]}"])
file.binmode
file.write(decoded_file)
file.close
#user.icon = open(file)
#user.icon_file_name = params[:user][:icon_file_name]
ensure
file.unlink
end
#user.save
I do an almost identical process on another model with a Paperclip attachment and it works flawlessly. In both cases the attachment is being saved correctly to S3 and no errors are being raised. This gist has example output for a controller action from the Heroku logs.
I am pretty baffled because the other model works fine. The only real difference is that the User attachment does image processing but that part appears to be working fine.
The problem is the same as this one, but the solution there does not apply.
Thoughts?
So the problem is that not including the :path argument makes it try to use the :url parameter for both the url and the path. The real fix is to include the :path parameter in addition to the url.
So for example a fixed configuration that works both locally and on Heroku:
has_attached_file :icon,
:url => "/system/:rails_env/:attachment/:style/:hash.:extension",
:path => "public/system/:rails_env/:attachment/:style/:hash.:extension",
:hash_data => ":class/:attachment/:id",
:hash_secret => "superDuperSecret",
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:default_url => "/blank.png"

Rails3 - how to get at aws-s3's yml config data in the app?

Specifically, i have a file config/amazon_s3.yml which is used by the aws-s3 gem to set up some s3 config settings like secret keys etc. I also write some of this data into a var in ENV in a different file in initializers so i can reference them in calls to the "has_attached_file" method used by paperclip.
It would be smarter to get the file in initializers to read them out of the s3 config yml, or some config settings for the classes used by the gem, eg something like AWS::S3::Base.connection.secret_access_key (this doesn't work).
Any ideas?
I found the answer here How to use YML values in a config/initalizer
First i load in the yaml in and stick it in a constant.
#config/initializers/constants.rb
S3_CONFIG = YAML.load_file("#{::Rails.root}/config/amazon_s3.yml")
Then, when i set up paperclip for a model, pull in these values, making sure i refer to the current environment:
class Entry < ActiveRecord::Base
has_attached_file :media,
:styles => {
:medium => "300x300>",
:thumb => "110x110>"
},
:storage => :s3,
:bucket =>S3_CONFIG[::Rails.env]["bucket"],
:s3_credentials => {
:access_key_id => S3_CONFIG[::Rails.env]["access_key_id"],
:secret_access_key => S3_CONFIG[::Rails.env]["secret_access_key"]
}
end

AWS::S3::MissingAccessKey in Paperclip but I've defined both

I'm on Heroku, and this is a portfolio thing which I'm putting up on github for potential employers to look at, so obviously I don't want to stick my keys in a S3.yml file. I've exported S3_KEY and S3_SECRET to my environment both on Heroku and my machine and ruby can access them. But when I try and upload, it gives me the following error:
AWS::S3::MissingAccessKey in Portfolio itemsController#update
You did not provide both required access keys. Please provide the access_key_id and the secret_access_key.
The trace is irrelevant except for my controller line #, which works fine until I try and upload a file. Here's what I have:
class Asset < ActiveRecord::Base
attr_accessible :image, :image_file_name, :image_content_type, :image_file_size, :portfolio_item_id, :order
has_attached_file :image,
:styles => {
:thumb => "100x100#",
:small => "300x300",
:large => "600x600>"
},
:storage => :s3,
:s3_credentials => {
:access_key_id => ENV["S3_KEY"],
:secret_access_key => ENV["S3_SECRET"]
},
:bucket => "bucketybucket",
:path => "portfolio"
end
Anyone know what's going on here? How am I constructing this hash wrong?
Oh, and I've followed this thread, no dice: Paperclip and Amazon S3 Issue
same problem...
seems like that ENV const doesn't load before loading the module. solve by using file argument
like this
:s3_credentials => Rails.root.join('config/amazon_s3.yml')
and in amazon_s3.yml
access_key_id: 'your_key'
secret_access_key: 'your_sec_key'
bucket: 'somebucket'
furthermore, you can set environment variable by using heroku config:add command, which is describe in Heroku DevCenter
The problem is because the Enviroment variable in heroku is different that the enviroment variable in your system, so it may happen that the application works just in one enviroment

Resources