Systematic way to upgrade from attachment_fu to carrierwave? - ruby-on-rails-3

I'm working on upgrading an app to Rails 3, and attachment_fu is broken so I'm moving to carrierwave. Is there a systematic process that I can go through to upgrade from attachment_fu to carrierwave? Or a tutorial for it? Right now, I'm more interested in getting everything on the database end right. I'm using the filesystem store option for attachment_fu and carrierwave.
I've found a module, UploaderFu from http://ruby.simapse.com/2011/03/migrate-attachmentfu-to-carrierwave.html that tells carrierwave to use the same directories and filenames as attachment_fu. But it's not the entire answer, just part of it.
For example, in the db, I have a UserImage model, with :filename, :content_type, :size, :width, :height, and :user_id attributes. I added a :user_avatar column, and the following to my model
attr_accessible :user_avatar
mount_uploader :user_avatar, UserAvatarUploader
What exactly gets stored in :user_avatar. Is it just the filename? or something else? Do I just need to write a migration to move the data in :filename (stored like "hello_world.png") to :user_avatar? If that's the case I should just use the original :filename instead of creating a :user_avatar column, right?

The column you mount the uploader on is supposed to store an "identifier" for the uploaded file. By default it's just the filename, but you can override it to be almost anything apart from the ID of the record (because you can't know what that is until after saving).
To override: in your uploader class, add this definition :
def identifier
# This is what gets put in the database column!
model.created_on
end
In this example I've used the created_on attribute from the model. If you want to create your own storage mechanism then you need to be able to uniquely identify files by this identifier so be careful what you choose.
I would suggest renaming the column so it describes the file that's being uploaded (like in the carrierwave example). Then you can always change the identifier from filename to something else later.

Related

PostgreSQL & DataMapper issues

Been scratching my head for a while on this one and despite trying many variations I cannot see the mistake. After writing the app file, which contains what looks like the correct DataMapper.setup code for using PostgreSQL (?), and upon trying to play around in IRB/PRY, i just get a 'FATAL database not created' message even after i have called 'Song.auto_migrate!', here is my code, can anyone help me get past this? Thanks in advance:
require 'data_mapper'
require 'dm-core' #main DataMapper gem
require 'dm-migrations' #extra DataMapper functionality extension
DataMapper.setup(:default, "postgres://localhost/development")
class Song
include DataMapper::Resource
property :id, Serial
property :title, String
property :lyrics, Text
property :length, Integer
property :released_on, Date
end
DataMapper.finalize
I require the file all fine in irb, then call Song.auto_migrate! and it runs the 'database does not exist' error. What am i doing wrong?
You need to do this in command line:
psql
and then
CREATE DATABASE development;
before even trying to run Data Mapper setup code.
Perhaps you are missing this line: DataMapper.auto_upgrade!
On a side note, remember that auto_migrate! will wipe any existing data, whereas auto_upgrade! doesn't: http://datamapper.org/getting-started.html

What is the best practice of storing single use user settings in rails 3?

I am struggling to find a pattern for storing single use user settings (VAT percentage, tag line. Things that are 1 off by nature) in Rails 3. I need to set up global site settings, which have single instances.
Ideally, I want the answer to be a design pattern, rather than a gem or plugin (unless someone knows a gem or plugin that integrates will with Active Admin)
What do you mean by single use settings? Do you mean things like API keys and environment variables?
If so, then a good practice is to use the ENV hash, and set up ENV variables in the environments file (explained below).
Create a .rb file for each individual gem (or arbitrary entity) that needs settings in your config/initializers/ directory. For example, when using stripe, I created config/initializers/stripe.rb shown below:
Rails.configuration.stripe = {
:publishable_key => ENV['STRIPE_PUBLISHABLE_KEY'],
:secret_key => ENV['STRIPE_SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
This sets up initial settings within my stripe gem, and pulls the variable values from the ENV hash.
To set variables in the ENV hash, you can do so within the config/environments directory. In that directory, you will have three different files: config/environments/test.rb, config/environments/development.rb, config/environments/production.rb. Setting variables in the ENV hash(as shown below).
AppName::Application.configure do
# Set Stripe API Key
ENV['STRIPE_SECRET_KEY'] = "sk_test_key"
ENV['STRIPE_PUBLISHABLE_KEY'] = "pk_test_key"
...
end
How about a class for storing your key-value pairs?
class Settings < ActiveRecord::Base
attr_accessible :lookup, :value
def self.VAT
return self.find_by_lookup('VAT')
end
end
Then you can do #vat = Settings.VAT.value or similar. The lookup is your internally defined key. Of course the value column will have to be all the same datatype, but you can handle any necessary transformation in the getter methods (or through subclasses).

Paperclip not saving attachment

I am unable to get Paperclip to save my attachment. Rather than saving a single image (such as an avatar as seems to be the common usage), I need to be able to upload/save multiple files; therefore I have a User model and an Asset model. The file information gets properly stored in the asset table, but the attachment itself is not saved in the filesystem as expected.
My log shows the message:
"[paperclip] Saving attachments."
but the attachment is not saved.
Here's a gist with the details: https://gist.github.com/1717415
It's gotta be something simple that I'm missing...
OK... found the problem and it's now working.
The first issue was my naming of the columns in the asset model. I had used simple names: i.e., :description, :file_name, :file_size, :content_type. What I needed to use was: :upload_description, :upload_file_name, :upload_file_size, :upload_content_type where the 'upload' (or whatever you want to use) is a prefix that Paperclip will recognize.And of course that changed my Asset model to reference :upload not :asset, as in:
has_attached_file :upload
Secondly (and this post Adding :multipart => true throws Undefined Method "name" error was key to understanding this) was that you cannot specify the full column name (:upload_file_name) in your view, just specify the prefix and Paperclip magically understands what you want.
Hope this helps someone else!
Did you install ImageMagick?
Did you added image_magick command_path via initializer?
if not, checkout this answer:
Weird paperclip error message

Ruby on Rails 3: rails_admin + puret?

Did someone try to integrate puret into rails_admin? I can't make a language switch to edit different translations :(
Changing I18n.locale forces whole rails_admin to use specified locale.
Now I got the solution. The two can work together well. In short:
Delete the pureted column(s) in your model
If you have the column pureted still in your model, rails form helper will bypass puret. That is, if a model called Post has a field called contents to be i18ned, the table posts SHOULD NOT have the column contents.
Actually we should use globalize3 instead. With this you do not need to remove the original column. And puret doens't support nested attributes assignment. globalize3 works very well.

Mongoid: Changing the order of documents in an embeds_many relation

I have a mongoid document which embeds other documents with a relation like
this:
embeds_many :blocks
Creating new blocks works fine, but I cannot manage to change the
order of existing embedded documents. For example I have three
embedded blocks and I want to move the last one to the first
position.What's the correct way to do that?
I had to deal with this with mongoid's recursively_embeds_many feature, but it's essentially the same. There's nothing wrong as far as I can tell with literally rewriting the document. Write a model method to do something like:
def reverse_blocks
reversed_blocks = blocks.to_a.reverse
blocks.clear
reversed_blocks.each do |b|
blocks.create b.attributes
end
save
end
That's not great code above, but it gives you an idea of how to do what you want to do. I'm not thrilled with having to go through that just to reorder stuff in an array, but there it is.
I think, that really correct way is make in your embedded docs field "weight" and query them with asc(:weight) or desc(:weight). You don't rely on the order of persisted non-embedded docs, so you shouldn't in embedded.
But if you urgently need to make this, your embedded docs in mongoid are just array, so you can do such way:
doc.embedded_docs = [doc.embedded_docs.last] + doc.embedded_docs[0..-2]