Paperclip not saving attachment on Padrino - ruby

I am building a site using padrino. I use paperclip for uploading logos to one of the models. The problem I am experiencing is that Paperclip does not save the attachment, but also does not throw any errors. I think that the parameters passed to the controller are of incorrect type, as the params[:logo] is a hash and should probably be a some kind of a file type? How can I make Paperclip save the attachments passed in the parameters?
The model:
class Charity < ActiveRecord::Base
include Paperclip::Glue
attr_accessible :name, :description, :logo
has_attached_file :logo, path: "/public/:attachment/:id/:basename.:extension"
end
The logo is set in the controller like so:
post :create do
#charity = Charity.new(params[:charity])
if #charity.save!
flash[:notice] = 'Charity was successfully created.'
redirect url(:charities, :edit, id: #charity.id)
else
render 'charities/new'
end
end
The form passing the parameters to the controller looks like this (parts omitted for brevity):
- form_for :charity, url(:charities, :create), multipart: true, class: :form do |f|
(...)
.group
==f.label :logo
==f.error_message_on :logo
==f.file_field :logo
(...)
I am using Paperclip 2.7.0 and Padrino 0.10.7.
I also have added this to boot.rb as per Using Paperclip with Padrino :
Padrino.before_load do
File.send(:include, Paperclip::Upfile)
Paperclip.options[:logger] = Padrino.logger
Paperclip.options[:command_path] = "/usr/local/bin"
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, Paperclip::Schema)
ActiveRecord::ConnectionAdapters::Table.send(:include, Paperclip::Schema)
ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Paperclip::Schema)
end

Mmm, I've no idea. Maybe this:
path: Padrino.root('/public/:attachment/:id/:basename.:extension')
Can you go in padrino console and try:
>> require 'open-uri'
>> puts Paperclip.default_options
>> c = Charity.create!
>> c.logo = open('http://1.bp.blogspot.com/-0Hn3AjTJj6U/TZHe3ragXGI/AAAAAAAAA1M/_SBk3dx61EE/s1600/med_funny-cat.jpg')
>> c.save!

Related

Sinatra + Paperclip : undefined method `descendants'

I'm currently converting a very small Rails application to Sinatra. This Rails app was relying on ActiveRecord + Paperclip + Amazon S3 for picture storage, and I have troubles making it work in Sinatra (but I believe it would be the same for any kind of Rack-based application), with ActiveRecord + Paperclip + Amazon S3 as well.
Here's what I have so far:
Gemfile:
gem 'paperclip'
gem 'paperclip-rack', require: 'paperclip/rack'
gem 'aws-sdk'
Model:
class Photo < ActiveRecord::Base
include Paperclip::Glue
has_attached_file :image,
:storage => :s3,
:s3_credentials => "config/s3.yml",
:bucket => 'mybucket',
:path => ':style/:photo_id.:extension',
:styles => {
:original => '1200x1200>',
:miniature => '80x80#',
:slideshow => 'x200'
}
end
View:
form method="post" action="/photos/add" enctype='multipart/form-data'
input type="file" name="image"
input#submit-button type="submit"
Route/Action:
post '/photos/add' do
photo = Photo.new
photo.image = params[:image]
#image[:tempfile] = params[:image][:tempfile],
#image[:filename] = params[:image][:filename],
#image[:content_type] = params[:image][:type],
#image[:size] = params[:image][:tempfile].size
photo.save
redirect "/"
end
And the error I'm getting when trying to upload something :
NoMethodError at /admin/photos/add
undefined method `descendants' for Paperclip::Validators::AttachmentFileNameValidator:Class
file: attachment.rb location: each line: 393
I've tried to play with the :image param in my route (and manually assign each value to the field that was created by paperclip, see the commented lines) but it didn't seem to work any better. Any idea guys ? I'm stuck and have no clue where to start to get this to work.
Note: I've removed all validations and stuff so I even don't understand the error message I'm getting.
I (think) I was able to monkey patch the #descendants method using this SO answer:
Look up all descendants of a class in Ruby
So I monkey-patched Paperclip in one of my initializers, which seemed okay to me since I don't care about validating the content type of the attachment:
module Paperclip
module Validators
class AttachmentFileNameValidator
def self.descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
class AttachmentContentTypeValidator
def self.descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
class AttachmentFileTypeIgnoranceValidator
def self.descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
end
end
I'm using Paperclip 4.2 and Sinatra 1.4.5
There is no official support for non-Rails apps using Paperclip. See a discussion on it here
You'll notice if you look in Paperclip::Validators::AttachmentFileNameValidator:Class you'll see:
class AttachmentFileNameValidator < ActiveModel::EachValidator
def initialize(options)
options[:allow_nil] = true unless options.has_key?(:allow_nil)
super
end
ActiveModel is bundled w/ rails, so I'm guessing it's blowing up on the inheritance in here. Either way, I'd move over to an uploader friendly to sinatra like carrierwave

Why does respond_with JSON not work?

I'm having a problem when trying to use the return to in a rails controller. This is not working:
class UsersController < ApplicationController
respond_to :json
def create
#user = User.create params[:user_info]
respond_with #user
end
end
This works:
class UsersController < ApplicationController
respond_to :json
def create
#user = User.create params[:user_info]
respond_with #user do |format|
format.json { render json: #user.to_json }
end
end
end
Why? This is the error I have in the server's log when using the one that doesn't work:
NoMethodError (undefined method `user_url' for #<UsersController:0x007fd44d83ea90>):
app/controllers/users_controller.rb:7:in `create'
My route is:
resources :users, :only => [:create]
responds_with tries to redirect to user_url, so it looks for a show method in your user controller, which you don't have, since your route is limited to the create method only. Since the create method redirects to the show method by default this doesn't work. But in your second version you are actually rendering something, so no redirection happens.
You can give a :location option to respond_with if that's what you want, like so:
respond_with(#user, :location => home_url)
or use the render version as you do in your second version.

How do you put dynamic content in an action mailer subject line?

I'm trying to put the name of my app in the subject line of emails that action mailer sends. I have no problem doing this with the default from email address, but when I try to add it to the subject it sends it through as plain text <%= app_name %>.
Here's my mailers/user_mailer.rb:
class UserMailer < ActionMailer::Base
add_template_helper(ApplicationHelper)
extend ApplicationHelper
default from: "#{app_name} <#{system_email}>"
def reset_password_email(user)
#user = user
#url = "#{root_url}/password_resets/#{user.reset_password_token}/edit"
mail(:to => user.email,
:subject => "Reset Your Password | #{app_name}")
end
end
And here's what I have in my application helper:
def app_name
'Tip Share'
end
def app_domain
'tipshare.herokuapp.com'
end
def system_email
'info#wingardcreative.com'
end
Neither #{app_name} or <%= app_name %> works. How do I do this?
Have you tried adding it like this:
include ApplicationHelper
By extending UserMailer with ApplicationHelper, those methods are available as class methods - which is why the reference in default from: "#{app_name} <#{system_email}>" works.
Within the reset_password_email method, app_name would be an undefined local variable.
So you either need to additionally include ApplicationHelper, or call it with self.class.app_name.

Couldn't find <object> without an ID rails 3.0.1

Unfortunately, this is my second post in as many days. So the application worked fine with mysql and rails 3.0.3 but I found out that I needed to use MSSQL so I had to downgrade rails to 3.0.1.
In a nutshell, I copied the show.html.erb as show2.html.erb and created a new method which is a copy of the show method. Then I created a route match.
my controller
class fathersController < ApplicationController
def show
#father= Father.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #father}
end
end
def show2
#father= Father.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #father}
end
end
end
routes.rb
resources :fathers do
match '/show2' => 'fathers#show2'
resources :kids
end
when I call
http://127.0.0.1:3000/father/1
I get the show view but when I call
http://127.0.0.1:3000/father/1/show2
I get the following error
Couldn't find father without an ID
The request Parameters come back as
{"father_id"=>"1"}
so I know that the problem is that the app is passing the id as father_id but how do I fix it? Any help would be appreciated.
There are two problems.
You're trying to use a non-resourceful route on a route that actually should be resourceful.
It looks like you're trying to send /show2 to a controller named hospitals, when your action is actually specified on the fathers controller.
This should do the trick:
resources :fathers do
get :show2, :on => :member
resources :kids
end
You can also write the above as:
resources :fathers do
member do
get :show2
end
resources :kids
end

rails 3 redirect_to pass params to a named route

I am not finding much info on how to do this even though there are lots of suggestions on how to pass params to a redirect using hashs like this redirect_to
:action => 'something', :controller => 'something'
in my app I have the following in the routes file
match 'profile' => 'User#show'
my show action loos like this
def show
#user = User.find(params[:user])
#title = #user.first_name
end
the redirect happens in the same user controller like this
def register
#title = "Registration"
#user = User.new(params[:user])
if #user.save
redirect_to '/profile'
end
end
The question is in the register action when I redirect_to how do I pass along the params so I can grab that user from the database or better yet ... I already have a user variable so how do I pass along the user object to the show action?
-matthew
If you're doing a redirect, Rails will actually send a 302 Moved response with a URL to the browser and the browser will send another request to that URL. So you cannot "pass the user object" as in Ruby, you can only pass some url encoded parameters.
In this case you would probably want to change your routing definition to:
match 'profile/:id' => 'User#show'
and then redirect like this:
redirect_to "/profile/#{#user.id}"
First off, I'd name your route, to make using it easier:
match '/profile/:id' => 'users#show', :as => :profile
You would then redirect to it, like so:
redirect_to profile_path(#user) # might have to use profile_path(:id => #user.id)
Then to pull the user from the database:
def show
#user = User.find(params[:id]) # :id comes from the route '/profile/:id'
...
end
As an aside, if you use something like Devise for authentication, it provides you with a current_user method, and therefore you wont need to pass around the user's id:
match '/profile' => 'users#show', :as => :profile
redirect_to profile_path
def show
#user = current_user
end

Resources