我正在使用Paperclip和S3在Rails 3应用程序中上传和存储文件。上传文件效果很好,但是当我尝试使用actionmailer将上传的文件附加到电子邮件时,我遇到了问题。经过大量的故障排除后,希望有人可以提供一些提示。
从高层来看,似乎我可能需要首先下载文件,在附加之前使用某种下载方法,这是建议的,但我并没有完全遵循如何实现 - paperclip + ActionMailer - Adding an attachment? < / p>
在应用程序中,用户上传文件(本例中为测验)后,应通过电子邮件通知管理员用户上传的文件。我一直在遇到“没有这样的文件或目录”。以下是我正在使用的代码。任何想法或建议将不胜感激!
Quiz.rb model - what users are uploading:
class Quiz < ActiveRecord::Base
attr_accessible :quiz_path, :user_id, :tutorial_id
validates_presence_of :quiz_path
validates_attachment_size :quiz_path, :less_than => 50.kilobytes
validates_attachment_presence :quiz_path
validates_attachment_content_type :quiz_path,
:content_type => ["application/pdf","application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
:message => 'We only accept Microsoft Excel files ending in .xlsx or .xls'
belongs_to :user
belongs_to :tutorial
has_attached_file :quiz_path,
:storage => :s3,
:s3_permissions => :private,
:path => "quizzes/:attachment/:style/:id.:extension",
:storage => :s3,
:s3_credentials => {
:access_key_id => ENV["AWS_ACCESS_KEY_ID"],
:bucket => ENV["S3_BUCKET_NAME"],
:secret_access_key => ENV["AWS_SECRET_ACCESS_KEY"]
}
end
AdminMailer类:
class AdminMailer < ActionMailer::Base
default from: "info@mydomain.com"
def admin_upload_notification_email(quiz, current_user)
@url = "http://mydomain.com"
@quiz = quiz
@user = current_user
mail(to: "me@mydomain.com", :subject => "New Upload From #{@user.email}")
attachments["#{quiz.quiz_path_file_name}"] = File.read("{quiz.quiz_path.expiring_url(60)}")
end
end
还添加了QuizzesController:
def create
@user = current_user
@quiz = @user.quizzes.create(params[:quiz])
respond_to do |format|
if @quiz.save
UserMailer.upload_notification_email(@user).deliver
AdminMailer.admin_upload_notification_email(@quiz, @user).deliver
format.html { redirect_to @user, notice: 'Your skill assessment answer file was successfully uploaded. We will review your responses and email you a link to your results as soon as possible.' }
format.json { render json: @user, status: :created, location: @quiz }
elsif @quiz.errors.any?
flash[:error] = 'Please make sure you selected your answer file and it ended in ".xlsx".'
return(redirect_to :back)
else
format.html { redirect_to @user, notice: 'No file was selected. Please back and choose "Select Your Answer File" before submitting.' }
format.json { render json: @quiz.errors, status: :unprocessable_entity }
end
end
end
答案 0 :(得分:20)
在弄乱了一些之后,能够让它运转起来。以下是对我有用的 - 希望它可以帮助某人。关键是使用open uri,因为测验文件在S3上。
class AdminMailer < ActionMailer::Base
require 'open-uri'
default from: "sales@mydomain.com"
def admin_upload_notification_email(quiz, current_user)
@url = "http://mydomain.com"
@quiz = quiz
@user = current_user
attachments["#{quiz.quiz_path_file_name}"] = open("#{quiz.quiz_path.expiring_url(60)}").read
mail(to: "admin@mydomain.com", :subject => "New Upload From #{@user.email}")
end
end
答案 1 :(得分:0)
就我而言,问题是在@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
try{
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
} catch (Exception e){
Log.e("Menu", "Full screen not supported under API 19 (4.4 KitKat)");
}
mainLinearLayout = (LinearLayout) findViewById(R.id.mainLinearLayout);
listView = (ListView) findViewById(R.id.listView);
listView.setItemsCanFocus(false);
listView.setDivider(null);
listView.setFocusable(false);
listView.setDividerHeight(0);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Channel channel = channels.get(position);
if (position == menuAdapter.getSelectedPosition()) {
if ((new Random(System.currentTimeMillis())).nextBoolean()) {
openChannel(channel);
} else {
tempChannel = channel;
Log.i("Menu", "Playing ad");
if (interstitialAd.isLoaded())
interstitialAd.show();
}
} else {
menuAdapter.setSelectedPosition(position, listView);
}
Picasso.with(mainActivity).load(channel.artUrl).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
BitmapDrawable bmDrawable = new BitmapDrawable(getResources(), bitmap);
if (bmDrawable != null)
bmDrawable.setAlpha(80);
mainLinearLayout.setBackground(bmDrawable);
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
}
});
mainActivity = this;
bannerAd = new AdView(this);
bannerAd.setAdSize(AdSize.BANNER);
bannerAd.setAdUnitId(getAdmobBannerId());
AdRequest adRequest = new AdRequest.Builder().build();
bannerAd.loadAd(adRequest);
interstitialAd = new InterstitialAd(this);
interstitialAd.setAdUnitId(getAdmobIntersitialId());
interstitialAd.setAdListener(new AdListener() {
@Override
public void onAdClosed() {
openChannel(tempChannel);
}
});
interstitialAd.loadAd((new AdRequest.Builder()).build());
mainLinearLayout.addView(bannerAd, 0);
new WebServiceJob().execute();
}
public String getAdmobBannerId() {
SharedPreferences preferences = getSharedPreferences("YTApp", MODE_PRIVATE);
String result = preferences.getString("admob_banner", null);
if (result == null) {
String defaultID = "ca-app-pub-";
preferences.edit().putString("admob_banner", defaultID).apply();
return defaultID;
}
return result;
}
public String getAdmobIntersitialId() {
SharedPreferences preferences = getSharedPreferences("YTApp", MODE_PRIVATE);
String result = preferences.getString("admob_intersitial", null);
if (result == null) {
String defaultID = "ca-app-pub4";
preferences.edit().putString("admob_intersitial", defaultID).apply();
return defaultID;
}
return result;
}
public void artDownloaded(){
numArtDownloaded++;
if(numArtDownloaded == channels.size())
updateUIWithScroll();
}
public void updateUIWithScroll(){
updateUI();
if(!menuAdapter.isScrolling) {
menuAdapter.isScrolling = true;
listView.post(new Runnable() {
@Override
public void run() {
Log.i("Menu", "Scrolling");
listView.smoothScrollToPosition(menuAdapter.getSelectedPosition());
menuAdapter.isScrolling = false;
}
});
}
}
public void updateUI() {
try {
ArrayList<String> channelNames = new ArrayList<>();
for (Channel channel : channels)
channelNames.add(channel.title);
menuAdapter = new MenuAdapter(this, R.layout.listitemright, channelNames, getSharedPreferences("YTApp", MODE_PRIVATE).getInt("selectedChannelNr", -1));
listView.setAdapter(menuAdapter);
if (menuAdapter.getSelectedPosition() != -1) {
Picasso.with(mainActivity).load(channels.get(menuAdapter.getSelectedPosition()).artUrl).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
BitmapDrawable bmDrawable = new BitmapDrawable(getResources(), bitmap);
if (bmDrawable != null)
bmDrawable.setAlpha(80);
mainLinearLayout.setBackground(bmDrawable);
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
}
} catch (Exception e){}
}
电话中指定了content_type: "text/html"
。删除它修复了我在Rails 4上的问题。
mail()
这样可以在Outlook和Gmail上正确呈现PDF文档附件,但应该可以在任何地方使用。