简体   繁体   中英

How can I use Paperclip gem for Rails in a class that does not inherit from ActiveRecord::Base?

There seems to be some people that have gotten Paperclip working on a regular ruby class by doing something like the following:

require "paperclip"

Class Person
   include Paperclip
   has_attached_file :avatar,{}
end

See here This does not work for me even when using the main Paperclip repo:

$ bundle exec rails c
>> Rails.version
=> "3.1.3"
>> require 'paperclip'
=> false
>> class Monkey
>> include Paperclip
>> has_attached_file :avatar,{}
>> end
NoMethodError: undefined method `has_attached_file' for Monkey:Class

Has anyone gotten this working and can possibly give a clue on what could be going wrong?

Thanks!

Paperclip is pretty explicitly for use with AR.

Another option is to use carrier wave instead which works pretty well outside AR, with a variety of ORMS, or none:

https://github.com/jnicklas/carrierwave

I recently had to figure this out. You need to use some ActiveModel stuff in defining your library class or model. Specifically, to use Paperclip, you need the following methods: save, destroy, their callbacks, to_key (for use with form_for), attr_acessors for id, and of course, *_file_name, *_file_size, *_content_type, *_updated_at for each attached file.

The following class should give you the minimum implementation you need. This "solution" uses Rails 3.2.8, Ruby 1.9.3, and Paperclip 3.2.0 as of Sept 10, 2012, although other configurations may work.

class Importer
    extend  ActiveModel::Callbacks
    include ActiveModel::Validations

    include Paperclip::Glue

    define_model_callbacks :save
    define_model_callbacks :destroy

    validate :no_attachement_errors

    attr_accessor :id, :import_file_file_name, :import_file_file_size, :import_file_content_type, :import_file_updated_at

    has_attached_file :import_file,
                      :path => ":rails_root/public/system/:attachment/:id/:style/:filename",
                      :url  => "/system/:attachment/:id/:style/:filename"

    def initialize(args = { })
      args.each_pair do |k, v|
        self.send("#{k}=", v)
      end
      @id = self.class.next_id
    end

    def update_attributes(args = { })
      args.each_pair do |k, v|
        self.send("#{k}=", v)
      end
    end

    def save
       run_callbacks :save do
       end
    end

    def destroy
      run_callbacks :destroy do
      end
    end

    # Needed for using form_for Importer::new(), :url => ..... do
    def to_key
      [:importer]
    end

    # Need a differentiating id for each new Importer.
    def self.next_id
      @@id_counter += 1
    end

    # Initialize beginning id to something mildly unique.
    @@id_counter = Time.now.to_i

  end

A form for a file upload may look like the following:

<%= form_for Importer.new, :url => import_nuts_path do |form| %>
   <%= form.file_field 'import_file' %>
   <%= form.submit 'Upload and Import' %>
<% end %>

and the NutsController would have the following action:

class NutsController < ActionController::Base
    def import
       importer = Importer.new(params[:importer])
       importer.save
    end
end

Note :: You have to call "save" or nothing will happen. Calling "destroy" will delete the file on the server side. Since this class is not persistent, you probably should do that after you are done with it in the controller, or you'll end up with a file space leak, if you don't do any clean up.

Security Note : This "solution" is not using any ActiveModel::MassAssignmentSecurity for new() and update_attributes(), but this class doesn't really need it. Your mileage may vary. Be careful out there!

Cheers,
-Dr. Polar

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM