Rails 3, Uploadify and Carierwave - ruby-on-rails-3

I am trying to implement an uploader using Carrierwave on the server and Uploadify on the client. From the client it seems like its all working and on the server the record gets saved in the db but the physical uploaded file is never saved to the file system. Please keep in mind that I am a newcomer to Rails.
Here is my uploader:
class ShapefileUploader < CarrierWave::Uploader::Base
storage :file
# simple path for debugging
def store_dir
"uploads"
end
end
My model:
class DataRecord < ActiveRecord::Base
# not too sure if this belongs here at all, documentation is not too specific.
require 'carrierwave/orm/activerecord'
mount_uploader :shapefile, ShapefileUploader
end
One thing i don't fully understand from the Carrierwave documentation is the part about making sure you are loading CarrierWave after loading your ORM. I don't fully understand what its means.
My controller:
class DataRecordsController < ApplicationController
skip_before_filter :verify_authenticity_token, :only => [:update, :create]
def index
#folder = Folder.find(params[:folder_id])
#data_types = DataType.all
end
def create
data_record = DataRecord.new({:shapefile => params[:Filedata], :folder_id => params[:folder_id], :user_file_name => params[:Filename], :data_type_id => 6})
data_record.save!
end
def update
end
end
In the create action asides from the actual file upload the rest of the data I am setting manually for debugging.
This all seems to work without any errors.
Here is the posted data:
Parameters: {"Filename"=>"id_rsa.pub", "Filedata"=>#<ActionDispatch::Http::UploadedFile:0x007fc67836eb88 #original_filename="id_rsa.pub", #content_type="application/octet-stream", #headers="Content-Disposition: form-data; name=\"Filedata\"; filename=\"id_rsa.pub\"\r\nContent-Type: application/octet-stream\r\n", #tempfile=#<File:/tmp/RackMultipart20120531-4919-147n4qu>>, "Upload"=>"Submit Query", "folder_id"=>"74"}
SQL INSERT:
INSERT INTO "data_records" ("data_type_id", "folder_id", "shapefile", "status", "uploaded_date_time", "user_file_name", "validated", "validation_results", "validation_to_send") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id" [["data_type_id", 6], ["folder_id", 74], ["shapefile", "id_rsa.pub"], ["status", 0], ["uploaded_date_time", nil], ["user_file_name", "id_rsa.pub"], ["validated", 0], ["validation_results", nil], ["validation_to_send", nil]]
I know there are some issues in regards to flash dropping cookies but I think I have worked around this for debugging purposes by skipping checking the authenticity token on the create action. I have changed the security permissions on the upload folder to world read/write. Another confusion I encountered on the github Carrierwave documentation is the following code:
u.avatar = File.open('somewhere')
Is this required? If so why and what does it do?
Help would be greatly appreciated. Thank You!

Figured it out! Uploaded files will be placed into /public/uploads. Likely a rookie mistake but would be nice if this was explained better in the documentation.

Related

Rails 3 inherited_resources ignores 'defaults' setting

I'm using Inherited resources for my controllers. And now i have model:
class Sms < ActiveRecord::Base
end
And i want controller for it, where i make defaults:
class Admin::SmsesController < Admin::InheritedResources
defaults :resource_class => Sms,
:collection_name => 'smses',
:instance_name => 'sms'
end
but i can not understand, why it still trying to get "Smse" model:
NameError in Admin::SmsesController#index
uninitialized constant Smse
Pls help.
The problem is that Rails doesn't know that the plural of Sms is Smses. If you go to the Rails console you should see that:
> "Sms".pluralize
=> "Sms"
> "Smses".singularize
=> "Smse"
When faced with a plural it doesn't recognise, singularize just truncates the final "s", which is why your app is looking for a nonexistent Smse model.
You will save yourself a lot of headaches by configuring Rails to pluralize/singularize your models correctly. In the file config\initializers\inflections.rb you should find some examples of how to do this. What you want is:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'sms', 'smses'
end
Then I don't think you should need to put the defaults option in there at all - it should all work out of the box.

Paperclip not saving files with save()

I have a little problem with paperclip saving the data passed through the form...
If I'm trying to save the record with .save() it won't save.. When I look in the server/log there are no errors or warnings for the paperclip gem :-/
# trying to save the record with save() -- not working :-/
def create
#baan_import = BaanImport.new(params[:baan_import])
if #baan_import.save
redirect_to(baan_imports_url)
else
render 'new'
end
end
Server-log: (using .save() in controller)
https://gist.github.com/1327347
I just don't get it why it's working if I'm using .create instead of .save()
# trying to save the record with Model.create() -- working!
def create
#baan_import = BaanImport.create(params[:baan_import])
redirect_to(baan_imports_url)
end
Server-log: (using .create() in controller)
https://gist.github.com/1327359
Can some one explain me why it's working with create and not with save??
Thanks,
Michael
Can you show us the BaanImport model. My first guess is you're possibly missing baan_upload in attr_accessible on your model, and as a result, Rails will not let you mass assign the file parameter for upload.
Can you also confirm (would appear as though it's properly set up) that your form has html => {:multipart => true} as an option?

multiple image upload with dragonfly

i was trying for multiple image upload with dragonfly in rails3. i searched for some tutorials, but couldn't find any. i found a tutorial for multiple image upload with Carrierwave, but couldnt find luck with dragonfly .. any help please :)
Preface
Dragonfly itself can be used to manage media for your project in general, similar to paperclip. The question itself boils down to the multiple file upload within a rails application. The some tutorials on this topic available, which can easily be adapted to models using Dragonfly for storing specific files on them. I would suggest you look into those and try to adapt them for your project.
However, I can present a minimum example which i built for a rails 3.2 app currently in development, which isn't perfect (validation handling for example), but can give you some starting points.
Example
Just for reference, the essential idea is taken from here. This example is done with Rails 3.2.x.
Let's say you have a vacation database, where users may create trip reports on vacations they took. They may leave a small description, as well as some pictures.
Start out by building a simple ActiveRecord based model for the trips, lets just call it Trip for now:
class Trip < ActiveRecord::Base
has_many :trip_images
attr_accessible :description, :trip_images
end
As you can see, the model has trip images attached to it via a has_many association. Lets have a quick look at the TripImage model, which uses dragonfly for having the file stored in the content field:
class TripImage < ActiveRecord::Base
attr_accessible :content, :trip_id
belongs_to :trip_id
image_accessor :content
end
The trip image it self stores the file attachment. You may place any restrains within this model, e.g. file size or mime type.
Let's create a TripController which has a new and create action (you can generate this via scaffolding if you like, it is by far nothing fancy):
class TripController < ApplicationController
def new
#trip = Trip.new
end
def create
#trip = Trip.new(params[:template])
#create the images from the params
unless params[:images].nil?
params[:images].each do |image|
#trip.trip_images << TripImages.create(:content => image)
end
if #trip.save
[...]
end
end
Nothing special here, with the exception of creating the images from another entry than the params hash. this makes sense when looking at the the file upload field within the new.html.erb template file (or in the partial you use for the fields on the Trip model):
[...]
<%= f.file_field :trip_images, :name => 'images[]', :multiple => true %>
[...]
This should work for the moment, however, there are no limitations for the images on this right now. You can restrict the number of images on the server side via a custom validator on the Trip model:
class Trip < ActiveRecord::Base
has_many :trip_images
attr_accessible :description, :trip_images
validate :image_count_in_bounds, :on => :create
protected
def image_count_in_bounds
return if trip_images.blank?
errors.add("Only 10 images are allowed!") if trip_images.length > 10
end
end
I leave this up to you, but you could also use client side validations on the file field, the general idea would be to check the files upon changing the file field (in CoffeeScript):
jQuery ->
$('#file_field_id').change () ->
#disable the form
for file in this.files
#check each file
#enable the form
Summary
You can build a lot out of existing tutorials, as dragonfly does not behave that differently to other solutions when it comes to just to uploading files. However, if you'd like something fancier, I'd suggest jQuery Fileupload, as many others have before me.
Anyways, I hope I could provide some insight.

TDD: Rspec Ruby MongoDB/Ruby Mongo Driver

how can I use TDD with MongoDB as my second database?
Thanks
Edit:
Using Rspec or anything else that allows me to test it.
[Update]
With MongoMapper set up you can easily use the mongodb connection directly
mongodb = MongoMapper.database
collection = mongodb.collection("my_collection")
collection.find.first
=> {"_id"=>BSON::ObjectId('4e43dfc75d1e1e0001000001'), "key1"=>"val1" }
this other SO Q/A is even more direct, using javascript functions like MongoMapper.database.eval(Mongo::Code.new('function(){ return 11 + 6; })
[/update]
I have such a polyglot architecture, some models with postgresql, others as mongo documents. I'm not really sure what you're asking, so I'll jump straight in and post most my configuration here. It includes my hacks, you probably find more beautiful config elsewhere.
I put the setup in a gist
https://gist.github.com/957341
OK, so here's a document with embedded document, then the spec. I wrote the specs one by one, so they're kinda test driven.
class MyDocument
include MongoMapper::Document
key :title, String
key :published_at, Time, :index => true
key :collaborators, Array
many :my_embedded_documents
end
class MyEmbeddedDocument
include MongoMapper::EmbeddedDocument
key :title, String
key :author, String
embedded_in :my_document
end
the spec
require "spec_helper"
describe MyDocument do
before do
#md = MyDocument.create(:title => "Example", :collaborators => ["mongomapper", "rspec", "oma"] )
end
it "should have title" do
found = MyDocument.find(#md.id)
found.title.should == "Example"
end
it "should have two my_documents" do
MyDocument.create
MyDocument.count.should == 2
end
it "should be able to fetch embedded documents" do
#md.my_embedded_documents << MyEmbeddedDocument.new(:title => "The King", :name => "Elvis Presley")
#md.my_embedded_documents.build(:title => "Embedded example", :name => "Embeddo")
#md.save!
MyDocument.where(:title => "Example").first.should == #md #findMyEmbeddedDocument.count.should == 2
end
end
spec_helper.rb
RSpec.configure do |config|
#...
config.after(:each) do
MongoMapper.database.collections.each(&:remove)
end
end
I don't know what you wanted for answers, but I hope this will be of help to somebody.
From what I can gather, it doesn't appear that your app is sticking to the rails MVC paradigm with its use of this secondary database that apparently doesn't store model data.
I would recommend taking the auxiliary parts of the app that depend on mongo and sticking them into a library. You can make this a gem if it makes sense to use it elsewhere. Then, create a testsuite for the logic of the library using standard testing tools, and integrate into your app either with a simple require, or some directives (depending on what it dies and how you intend to use it).

rails 3 response format and versioning using vendor MIME type in the Accept header

Preamble:
I investigated how to version an API and found several ways to do it. I decided to try peter williams' suggestion and created new vendor mime types to specify version and format. I could find no definitive write-up for doing this following "the rails way" so I pieced together info from several places. I was able to get it working, but there is some goofiness in the way the renderers handle Widget array vs Widget instance in respond_with.
Basic steps & problem:
I registered mime types and added renderers for version 1 in both xml and json to ApplicationController, the renderers call to_myproj_v1_xml and to_myproj_v1_json methods in the model. respond_with(#widget) works fine but respond_with(#widgets) throws an HTTP/1.1 500 Internal Server Error saying that the "Template is missing".
Workaround:
"Template is missing" means that no render was called and no matching template exists. by accident, I discovered that it is looking for a class method... so I came up with the code below which works but I'm not really happy with it. The goofiness is mostly in and related to xml = obj.to_myproj_v1_xml(obj) and the duplication in the model.
My question is - has anyone done anything similar in a slightly cleaner fashion?
-= updated code =-
config/initializers/mime_types.rb:
Mime::Type.register 'application/vnd.com.mydomain.myproj-v1+xml', :myproj_v1_xml
Mime::Type.register 'application/vnd.com.mydomain.myproj-v1+json', :myproj_v1_json
app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :authenticate
ActionController.add_renderer :myproj_v1_xml do |obj, options|
xml = obj.to_myproj_v1_xml
self.content_type ||= Mime::Type.lookup('application/vnd.com.mydomain.myproj-v1+xml')
self.response_body = xml
end
ActionController.add_renderer :myproj_v1_json do |obj, options|
json = obj.to_myproj_v1_json
self.content_type ||= Mime::Type.lookup('application/vnd.com.mydomain.myproj-v1+json')
self.response_body = json
end
end
app/models/widget.rb:
class Widget < ActiveRecord::Base
belongs_to :user
V1_FIELDS = [:version, :model, :description, :name, :id]
def to_myproj_v1_xml
self.to_xml(:only => V1_FIELDS)
end
def to_myproj_v1_json
self.to_json(:only => V1_FIELDS)
end
def as_myproj_v1_json
self.as_json(:only => V1_FIELDS)
end
end
app/controllers/widgets_controller.rb:
class WidgetsController < ApplicationController
respond_to :myproj_v1_xml, :myproj_v1_json
def index
#widgets = #user.widgets
respond_with(#widgets)
end
def create
#widget = #user.widgets.create(params[:widget])
respond_with(#widget)
end
def destroy
#widget = #user.widgets.find(params[:id])
respond_with(#widget.destroy)
end
def show
respond_with(#widget = #user.widgets.find(params[:id]))
end
...
end
config/initializers/monkey_array.rb
class Array
def to_myproj_v1_json(options = {})
a = []
self.each { |obj| a.push obj.as_myproj_v1_json }
a.to_json()
end
def to_myproj_v1_xml(options = {})
a = []
self.each { |obj| a.push obj.as_myproj_v1_json } # yes this is json instead of xml. as_json returns a hash
a.to_xml()
end
end
UPDATE:
Found another solution that feels better but still a little weird (I'm still not completely comfortable with monkey patches), probably ok though... basically moved building the response data from the class method to_myproj_v1_json to a monkey patch on Array. This way when there is an Array of Widgets, it calls the instance method as_myproj_v1_json on each Widget and returns the whole Array as desired format.
One note:
as_json has nothing to do with json format, just creates a hash. Add custom formatting to as_myproj_v1_json (or an as_json override if you aren't using custom mime types), then to_json will change a hash to a json string.
i have updated the code below to be what is currently used, so the original question may not make sense. if anyone wants the original question and code shown as was and fixed code in a response i can do that instead.
For the answer: see the question :-)
In short, there are different solutions, of which one is in the question above:
Monkey-patch Array to implement a method that will give the (old) v1 JSON back
I haven't seen this content type trick used anywhere in a Rails project before so this is new to me. The way I've typically seen it done is to define a route namespace (e.g. /api/v1/) which goes to a controller (say, Api::Version1Controller).
Also, I know you want to do things the "Rails way", and maybe this sounds crotchety coming from a guy who has been with Rails since 1.3, but the whole respond_with / respond_to stuff is rather magic to me. I didn't know that respond_to looks for a to_XXX method when it serializes objects, for instance (maybe I need to read up on that). Having to monkey-patch Array like that seems rather silly. Besides, for an API, formatting the model data is really the view's job, not the model's. I might look into something like rabl in this case. There's a good writeup about it here.