Im trying to add attachments to the contact form on this site Im making but I cant get action mailer to attach the uploaded file. I have paperclip uploading the file to S3 but I cant get it to grab the file and attach it to the message.
My app stack is: Heroku, Rails 3, and paperclip uploading to S3, heres what I have so far:
def contact_notification(sender)
#sender = sender
if attachments.count > 0
# Parse the S3 URL into its constituent parts
uri = URI.parse #sender.photo.url(:original).authenticated_url
# Use Ruby's built-in Net::HTTP to read the attachment into memory
response = Net::HTTP.start(uri.host, uri.port) { |http| http.get uri.path }
# Attach it to your outgoing ActionMailer email
attachments[#sender.attachment_file_name] = response.body
end
mail(:to => xxx)
end
What am I doing wrong? Im still a rails noob so Im piecing this together.
A quick note:
Amazon now requires
gem 'aws-sdk', :require => "aws-sdk"
instead of the s3 gem listed above.
If you don't have an s3 account already go get one here:
http://aws.amazon.com/s3/
You need to add this to your contact model:
app/models/contact.rb
has_attached_file :picture,
:styles => {:large => "275x450>"},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => "appname/:attachment/:style/:id.:extension"
Make sure you appname is your rails app name on heroku. And make sure you rename picture to whatever you have named your picture.
Then you need a config file in config/s3.yml.
development:
bucket: bucked_name
access_key_id: key
secret_access_key: secret
production:
bucket: bucked_name
access_key_id: key
secret_access_key: secret
Make sure you get the key and secret correct.
In your gem file make sure you have these gems install :
gem "aws-s3", :require => "aws/s3"
gem "paperclip"
Then in your form you need a file field and declare the form a multipart:
<% form_for(#contact, :html => {:multipart => true}) do |f| %>
<p><%= f.file_field :picture %></p>
<% end %>
And that should do it.
If you don't have an s3 account already go get one here:
http://aws.amazon.com/s3/
You need to add this to your contact model:
app/models/contact.rb
has_attached_file :picture,
:styles => {:large => "275x450>"},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => "appname/:attachment/:style/:id.:extension"
Make sure you appname is your rails app name on heroku. And make sure you rename picture to whatever you have named your picture.
Then you need a config file in config/s3.yml.
development:
bucket: bucked_name
access_key_id: key
secret_access_key: secret
production:
bucket: bucked_name
access_key_id: key
secret_access_key: secret
Make sure you get the key and secret correct.
In your gem file make sure you have these gems install :
gem "aws-s3", :require => "aws/s3"
gem "paperclip"
Then in your form you need a file field and declare the form a multipart:
<% form_for(#contact, :html => {:multipart => true}) do |f| %>
<p><%= f.file_field :picture %></p>
<% end %>
Then mail your contact with the picture. You said that you were using rails 3?
So in your contact model:
class Contact << ActiveRecord::Base
before_save :mail_user
def mailer_user
ContactMailer.contact_notification(#user).deliver
end
end
Then in your mailer (assuming you are on Rails 3):
class ContactMailer < ActionMailer::Base
default :from => "sam#codeglot.com"
def contact_notification(#user)
#subscription = "test"
#url = "test"
mail(:to => "test#test.com",
:subject => "Test")
end
end
So in your mailer view you need to include and image tag like so:
<%= image_tag(#contact.picture(:small)) %>
Then you just need to send you email after a contact is created and include the attachment.
Related
I have been scouring through SO posts for the last day and a half, and have asked another question related to this issue here, and have yet to come up with a solution. I am unable to render my images, which are being correctly uploaded to AWS in my view using <%= image_tag #user.avatar.url(:medium) %> as specified in the documentation.
Looking in my DB, all of the fields related to the avatar are indeed populated with:
avatar_file_name => meditation.jpg
avatar_content_type => image/jpeg
avatar_file_size => 109992
avatar_updated_at => 2016-08-04 06:48:31.361434
and the image can be viewed in the browser by double clicking on the image's link in my amazon bucket: https://s3.amazonaws.com/giving-tree-images/Users/sgau677/giving_tree/public/avatars/12/medium/meditation.jpg.jpg
As you can see, for some reason a double file extension is being appended, which is a separate issue (that I welcome feedback on) but which does not seem to be the issue, as I am not able to render in the view uploaded images with a single file extension either.
So with the images being uploaded, the db fields being populated, and no errors - I am at a loss as to why I cannot render them in the view. I suspect the issue is either 1) the path -which looks like this in my model:
has_attached_file :avatar,
:styles => { medium: "300x300#", thumb: "100x100#" },
:convert_options => {
:thumb => "-quality 75 -strip" },
:s3_host_name => "s3.amazonaws.com",
:path => ":rails_root/public/:attachment/:id/:style/:filename.:extension",
:url => ":attachment/:id/:style/:filename.:extension",
:default_url => "default_img.png",
:storage => :s3,
:s3_credentials => {
:bucket => 'giving-tree-images',
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
},
:s3_permissions => {
:original => 'public-read'
}
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
attr_accessor :avatar_file_name, :avatar_content_type, :avatar_file_size, :avatar_updated_at
Which as you can see seems to be correct (unless I should be taking out the :rails_root bit in my model?)
or 2) I need to somehow save the location of the images in a separate model (which I have seen other ppl do, but am not sure it is required, as others seem not to have done this - granted they may just not have mentioned that they did). This being a step has not been in any of the docs I have read however.
3) I also wonder if there is possibly a separate process that I need to be doing in development as opposed to production?
or 4) I am using rails 4.2.3 and have read in comments that paperclip does not support versions of aws > 2.00 - however the Heroku docs - instructed to use 2.3...so perhaps this is the issue?
gem "paperclip", "~> 5.0.0"
gem 'aws-sdk', '~> 2.3'
I have also set up, in following other posts, a config/asw.yml file that looks like this:
development:
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
production:
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
although I am not sure it is being read (where the ENV var's are stored in secrets.yml, as well as both locally and on heroku via terminal) and a config/s3.yml file that looks like this:
include 'secrets.yml'
development:
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
bucket: <%= ENV["S3_BUCKET_NAME"]%>
production:
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
bucket: <%= ENV["S3_BUCKET_NAME"]%>
an initializers/s3.rb
if Rails.env == "production"
# set credentials from ENV hash
S3_CREDENTIALS = { :access_key_id => ENV['AWS_ACCESS_KEY_ID'], :secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'], :bucket => "giving-tree-images"}
else
# get credentials from YML file
S3_CREDENTIALS = Rails.root.join("config/s3.yml")
end
and modified my both environments/development.rb and my environments/production.rb to include:
config.paperclip_defaults = {
storage: :s3,
:s3_host_name => "s3.amazonaws.com",
s3_credentials: {
bucket: ENV.fetch('S3_BUCKET_NAME'),
access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
s3_region: ENV.fetch('AWS_REGION'),
}
}
...as per multiple other posts combined suggested. It is quite possible I do not need all of this, so if anyone can help as to what I should be getting rid of, and why I cannot render images in the view - I would REALLY appreciate it as this is maddening.
You are putting extension after :filename for both the :path and the :url -- but you shouldn't.
:filename includes the extension. That is why you are getting the extension twice.
You have this in your model:
:path => ":rails_root/public/:attachment/:id/:style/:filename.:extension",
:url => ":attachment/:id/:style/:filename.:extension",
and after you remove .:extension, you should have this:
:path => ":rails_root/public/:attachment/:id/:style/:filename",
:url => ":attachment/:id/:style/:filename",
I am building a Rails 4 app with admin uploads of large files to Amazon S3. To validate the transfer of the large files, I would like to include the Content-MD5 field in the request header per the Amazon docs:
http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html
I started with Paperclip + S3 and the MD5 verification is working:
has_attached_file :file,
:storage => :s3,
:bucket => AppSetting.s3_bucket,
:s3_credentials => Proc.new{|a| a.instance.s3_credentials },
:s3_permissions => :private,
:s3_headers => Proc.new{|a| a.s3_headers },
:path => "uploads/:id/:basename.:extension"
def s3_credentials
{:access_key_id => AppSetting.aws_access_key_id, :secret_access_key => AppSetting.aws_secret_access_key}
end
# md5sum is a value entered by the user as a string (hex notation)
# ex: "7d592a3129ab6a867cf6e2eb60f9ef83"
#
def encoded_md5sum
[[md5sum].pack("H*")].pack("m0")
end
def s3_headers
{:content_md5 => encoded_md5sum}
end
With Paperclip, the large file is first uploaded to my server, then transferred to Amazon S3. This blocks the Rails process and consumes redundant bandwidth, so I am trying to use the S3UploadDirect gem to upload the file directly the S3 bucket:
https://github.com/waynehoover/s3_direct_upload
This gem is a wrapper around the code from Railscasts episode 383 and uses jquery-fileupload-rails for the actual upload:
<%= s3_uploader_form callback_url: "#{AppSetting.host_base_url}/admin/uploads",
callback_method: "POST",
callback_param: "upload[file_url]",
key: "uploads/{timestamp}-{unique_id}-#{SecureRandom.hex}/${filename}",
key_starts_with: "uploads/",
acl: "private",
bucket: AppSetting.s3_bucket,
aws_access_key_id: AppSetting.aws_access_key_id,
aws_secret_access_key: AppSetting.aws_secret_access_key,
max_file_size: 5.gigabytes,
id: "s3-uploader",
class: "upload-form",
data: {:key => :val} do %>
<%= file_field_tag :file, multiple: true %>
<% end %>
<script id="template-upload" type="text/x-tmpl">
<div id="file-{%=o.unique_id%}" class="upload">
{%=o.name%}
<div class="progress"><div class="bar" style="width: 0%"></div></div>
</div>
</script>
I can upload the file, but I cannot figure out how to pass the Content-MD5 information into the upload request header.
Cant find a way for S3 to work with spree. There seem to exist few gems for that but dont seem to work for me.
Running rails 3.1.1 with spree 0.70.3.
I am running rails 3.0.10 and spree 0.60 and was able to get spree to use s3 storage over writing to the public folder of the app by doing the following The process should be alike.
add aws-s3 gem to your Gemfile
gem 'aws-s3'
bundle installed and after doing that I created a yaml file in the config directory called s3.yml and it should look something like this.
development: &DEFAULTS
bucket: "YOUR_BUCKET"
access_key_id: "YOUR_ACCESS_KEY"
secret_access_key: "YOUR_ACCESS_SECRET"
test:
<<: *DEFAULTS
bucket: "YOUR_BUCKET"
production:
<<: *DEFAULTS
bucket: "YOUR_BUCKET"
You can specify individual credentials per environment if you like but since mine are all using the same S3 accont I opted to set defaults.
after that you are going to have to override the image model or make a decorator for your which tells paperclip to use S3 and to have it parse the yaml file created for credentials.
the area you want want to override would be this
has_attached_file :attachment,
:styles => {:mini => '48x48>', :small => '200x100>', :product => '240x240>', :large => '600x600>'},
:default_style => :small,
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:url => "/assets/products/:id/:style/:basename.:extension",
:path => ":rails_root/public/assets/products/:id/:style/:basename.:extension"
you can change these properties as needed but whats important is that you specify :storage and :s3_credentials.
In the current version of Spree, you can set these values in the admin tools. But if you prefer to maintain it in code but without overriding the Image model, you can set these values in config/initializers/spree.rb. Make sure not to edit them via the admin portal.
S3_CONFIG = YAML.load_file("#{Rails.root}/config/s3.yml")[Rails.env]
Spree.config do |config|
config.attachment_styles = ActiveSupport::JSON.encode({
"mini" => "100x100>",
"small" => "200x200>",
"medium" => "400x600>",
"product" => "400x600>",
"large" => "600x600>",
"xl" => "800x800>",
"xxl" => "1200x1200>",
})
#AWS S3
config.use_s3 = true
config.s3_bucket = S3_CONFIG['bucket']
config.s3_access_key = S3_CONFIG['access_key_id']
config.s3_secret = S3_CONFIG['secret_access_key']
config.attachment_url = 'products/:id/:style/:basename.:extension'
config.attachment_path = 'products/:id/:style/:basename.:extension'
end
You can also try the BitNami Spree AMIs at http://bitnami.org/stack/spree. Regards.
I'm pretty new to rails and seem to be having an issue with the paperclip gem. I installed the gem and it works well in development (localhost:3000) but when I'm running it on the heroku server, for some reason it does not want to attach files, and the app breaks (error 500 page).
Here is the process i ran... I pushed my file to heroku, heroku ran rake db:migrate (to add paperclip migrations), and then I ran heroku restart (to restart the app with new migrations). This did not seem to help.
Here is the code that I have for paperclip:
user.rb model:
has_attached_file :avatar,
:styles => {:small => "70x70>"},
:url => "/users/:attachment/:id/:style/:basename.:extension",
:path => ":rails_root/public/users/:attachment/:id/:style/:basename.:extension"
validates_attachment_size :avatar, :less_than => 500.kilobytes
validates_attachment_content_type :avatar, :content_type => ['image/jpeg', 'image/png']
edit_form.html.haml view:
= form_for (#user || User.new), :html => { :multipart => true } do |f|
...
.profile_picture.text_field
= image_tag current_profile.avatar.url(:small)
%br
= f.file_field :avatar
Again, for some reason it runs great in development, but breaks down in production. Any pointers would be greatly appreciated... I just cant seem to figure this out and it's pretty frustrating. Thank you so much for your time and any help!
In your model.
has_attached_file :picture,
:styles => {:large => "275x450>"},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => "appname/:attachment/:style/:id.:extension"
In s3.yml in your config dir:
development:
bucket: bucketname
access_key_id: key
secret_access_key: key
production:
bucket: bucketname
access_key_id: key
secret_access_key: key
Then go signup for a bucket at Amazon S3: http://aws.amazon.com/s3/
You could be having a few problems. However, the first is that you can not write to the file system on Heroku. You will have to implement a different storage mechanism such as s3. You can read about this limitation here: http://devcenter.heroku.com/articles/read-only-filesystem
How do you get http://github.com/galetahub/rails-ckeditor working so you can upload image files? I don't think I'll use the s3 storage...
any help would be appreciated.
Yes you can. I assume that you have paperclip already set up for S3. So you have only edit the picture.rb and attachement_file.rb in you model directory (app/model/ckeditor/) and replace these lines
has_attached_file :data,
:url => "/ckeditor_assets/attachments/:id/:filename",
:path => ":rails_root/public/ckeditor_assets/attachments/:id/:filename"
with your papeclip version has_attached_file:
has_attached_file :data, :styles => { :content => '575>', :thumb => '80x80#' },
:storage => :s3, :s3_credentials => "#{Rails.root}/config/s3.yml", :path => ":attachment/:id/:style.:extension",
:url => ":s3_domain_url"
That's it. Btw: this is example from Rails 3.
I would follow the README for the rails-ckeditor plugin you mentioned. If you don't need the SWFUpload, you can simply integrate the CKEditor and Paperclip, by writing a custom file uploader and custom file browser, and connect them to the editor by specifying urls and callback functions.
It is always useful to have an example, the author has made an example app. Unfortunately, there are a few errors in it. Consider the following points to make it running
change the following lines in config/environment.rb
config.gem 'paperclip', :version => '2.3.3'
config.gem 'ckeditor', :version => '3.4.1'
delete the file index.html in public
add a root route to config/routes.rb
map.root :controller => "pages"
Rails 4.2.0 solution:
How do you get http://github.com/galetahub/rails-ckeditor working so you can upload image files?
As is, CKEditor allows you to embed existing image URLs, but for CKEditor and Paperclip to work together so you can upload images, you will need ImageMagick. As I understand, it handles uploading the image data, making an image URL reference for the uploaded image data and the embedding of the uploaded image data's URL.
CKEditor
Add gem "ckeditor" to your Gemfile
then run the $ bundle install command.
Add this to /app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require ckeditor/init <--------------- THIS
//= require_tree . <----------------------- ABOVE THIS
per: https://github.com/galetahub/ckeditor#how-to-generate-models-to-store-uploaded-files
Add this to:
/config/routes.rb
I put it before the resources which utilize it
mount Ckeditor::Engine => '/ckeditor'
Using "form_for" and having set up an "Article" model with a title:string and text:text
/app/views/articles/_form.html.erb
<p>
<%= f.label :text %><br>
<%= f.cktext_area :text, rows: 10 %> # <-------- "cktext_area"
</p>
Using "simple_form_for"
<div class="form-group">
<%= f.input :body, :as => :ckeditor, input_html: {:ckeditor => {:toolbar => 'FULL'}}, class: "form-control" %>
</div>
Paperclip
per: https://richonrails.com/articles/getting-started-with-ckeditor
Add gem "paperclip" to your Gemfile and $ bundle install.
Then run the following two commands:
$ rails generate ckeditor:install --orm=active_record --backend=paperclip
and
$ rake db:migrate
ImageMagick
For macOS Sierra:
$ brew install imagemagick
For other ImageMagick install options: https://www.imagemagick.org/script/install-source.php
Use following things it working for me but you should have account on Amazon for s3 storage and correct endpoint you can refer following
code.`gem 'aws-sdk', '~> 2'
gem 'aws-s3'
gem 'aws-sdk-v1'
gem 'paperclip'
class Ckeditor::Picture < Ckeditor::Asset
AWS_CONFIG = YAML.load(ERB.new(File.read("#{Rails.root}/config/aws.yml")).result)[Rails.env]
has_attached_file :data,
s3_credentials: {
access_key_id: AWS_CONFIG['access_key_id'],
secret_access_key: AWS_CONFIG['secret_access_key'],
bucket: AWS_CONFIG['bucket'],
},
s3_host_name: 's3.amazonaws.com',
:s3_endpoint => 's3.amazonaws.com',
storage: :s3,
s3_headers: { "Cache-Control" => "max-age=31557600" },
s3_protocol: "https",
bucket: AWS_CONFIG['bucket'],
url: ':s3_domain_url',
path: '/:class/:attachment/:id_partition/:style/:filename',
default_url: "/:class/:attachment/:id/:style/:basename.:extension",
default_style: "medium"
validates_attachment_size :data, :less_than => 2.megabytes
validates_attachment_presence :data
def url_content
url(:content)
end
end
`
comment this line require "ckeditor/orm/active_record" from /config/initializers
finally put this line in <%= f.cktext_area :body %> view file.
In addition to Zaparka's response, I had to remove #{Rails.root} as I was getting an unitialized constant error. SO instead I put "/config/s3.yml", and that worked.