Custom configuration in rails 3 - ruby-on-rails

Background
I'm writing a photo gallery, the gallery can create both previews and thumbnails.
I want the user to customize the creation of these (resolution etc)
What I have so far
config/gallery.yml - Stores the actual settings, a block for each env
config/initializers/gallery.rb - Loads the YAML file into Gallery::Application
app/models/image.rb - The model that reads the configuration and creates the images
My question
Where is the best place to merge the settings with the default values?
I could either do it in gallery.rb or image.rb where it's actually used.
Otherwise, is this a sane approach or have I gone about this all wrong?
Any feedback is greatly appreciated.
Files
config/initializers/gallery.yml
production:
create_previews: true
create_thumbnails: true
development:
create_thumbnails: true
create_previews: true
test:
create_thumbnails: false
create_previews: false
config/initializers/gallery.rb
Gallery::Application.config.image_directory = File.join(Rails.root, 'images')
Gallery::Application.config.thumbnail_directory = File.join(Rails.root, 'thumbnails')
Gallery::Application.config.preview_directory = File.join(Rails.root, 'previews')
# DO NOT MODIFY THE LINES BELOW
EXTERNAL_CONFIG_FILE_PATH = "#{Rails.root}/config/gallery.yml"
if FileTest.exists? EXTERNAL_CONFIG_FILE_PATH
vals = YAML.load_file(EXTERNAL_CONFIG_FILE_PATH)[::Rails.env]
else
vals = {}
end
Gallery::Application.config.create_previews = vals['create_previews']
Gallery::Application.config.preview_settings = vals['preview_settings']
Gallery::Application.config.create_thumbnails = vals['create_thumbnails']
Gallery::Application.config.thumbnail_settings = vals['thumbnail_settings']

I also agree this is good place in config/initializers.
but other place and way is read/write database table field in GalleryConfig ActiveRecord model using MySQL.
because easy for testcase or rails console.

Related

Show square brackets in yml file

How to generate content in yml file with this format:
required_groups:
- ["member", "cn=serviceboard-users,cn=groups,cn=accounts,dc=int,dc=dostack,dc=io"]
Instead of this format:
required_groups:
- - member
- cn=serviceboard-users,cn=groups,cn=accounts,dc=int,dc=dostack,dc=io
Input:
[["member", "cn=serviceboard-users,cn=groups,cn=accounts,dc=int,dc=dostack,dc=io"]]
Current Code:
File.open("config/ldap/#{Rails.env}.yml", "w") do |file|
data = {}
formatted_groups_array = []
Setting.ldap_users_filter_required_groups.each { |group| formatted_groups_array.push([Setting.ldap_group_membership_attribute.to_s, group.to_s])}
data["required_groups"] = formatted_groups_array
file.write(data.to_yaml)
end
As stated in this answer, the default ruby library Psych does not have many options available, and you cannot customize the output the way you are trying to do.
In the meantime I've found an old possibile custom solution to your problem, but I had to rewrite a small part of it to make it compatible to the most recent ruby version (I am using 2.7.0 for this example). This is my updated script. Basically it will introduce a new way to edit the YAML output using a more concise syntax.
You can use it this way:
File.open("config/ldap/#{Rails.env}.yml", "w") do |file|
data = {}
formatted_groups_array = []
Setting.ldap_users_filter_required_groups.each { |group| formatted_groups_array.push([Setting.ldap_group_membership_attribute.to_s, group.to_s])}
data["required_groups"] = formatted_groups_array
styled_yaml = StyledYAML.inline(data)
file.write(StyledYAML.dump(styled_yaml))
end

Use gem 'postgres-copy' to import csv file

currently, I want to import above 55,000 records into my database from a CSV file. This is the code that I am using:
CSV.foreach(Rails.root.join('db/seeds/locations.csv'), headers: true) do |row|
val = Location.find_or_initialize_by(code: row[0])
val.name = row[1]
val.ecc = row[2] || 'MISSING'
val.created_by = User.find_by(name: 'anh')
val.updated_by = User.find_by(name: 'anh')
val.save!
end
However, it is too slow and I have just installed the gem 'postgres-copy'. I read the official documentation, and I believe I can use the class method copy_from to do the job, but if you read my current code, you can see that I am referring the data to the another table(association), and the documentation doesn't mention anything about association or validation. Therefore, I am wondering if there are any ways to solve it. This is the first time I use this gem. Thanks for reading.
I don't know that gem, but I would be very surprised if it can support multi-table copy since PostgreSQL's COPY works on a single table. 50K rows isn't all that many. You might try wrapping your insertions in transactions to avoid one commit per transaction. Doubt you want to wrap all 50K in a transaction though, but something like this:
User.connection.begin_transaction
i = 0
CSV.foreach(...) do |row|
... # your original code here
i += 1
if i % 500 == 0
User.connection.commit_transaction
User.connection.begin_transaction
end
end
User.connection.commit_transaction
This will insert your rows 500 records at a time and you should see a noticeable speed up. Play around with the value of 500 to find the sweet spot.
So, now I understand that I cannot take advantage of the COPY command in POSTGRESQL since it can't copy multiple tables. Therefore, I switch to the gem activerecord-import. Comparing with the method that Philip Hallstrom mentioned above, using activerecord-import give a faster result, 1m20s vs 1m54s to import above 8000 records.
This is my code after installing the gem activerecord-import. Hopefully, it can help other people.
locations = []
columns = [:code, :name, :ecc]
CSV.foreach(Rails.root.join('db/seeds/locations.csv'), headers: true) do |row|
val = Location.find_or_initialize_by(code: row[0])
val.name = row[1]
val.ecc = row[2] || 'MISSING'
val.created_by = User.find_by(name: 'anh')
val.updated_by = User.find_by(name: 'anh')
locations << val
end
Location.import columns, locations, validate: false

ThinkingSphinx config match_mode and distributed index problems

Have been struggling with ThinkingSphinx 3.0.5 for a couple of days. basically,
we use distributed indexes, so for one model 4 indexes were defined.
index post_core
{
type = distributed
local = post_core_i0
local = post_core_i1
local = post_core_i2
local = post_core_i3
}
how to make TS search to point to this distributed index? :index => 'post_core' doesn't seem to work.
We need a custom parameter like dictionary = /home/user1/../my.txt in the final config file -- how to make rake ts:configure to keep it?
how to set match mode to any? :match_mode => :any doesn't work
Thanks!

Saving images with Carrierwave inside a ruby worker

I'm trying to write a method to store an image from a given url, inside a ruby worker. It comes along my Rails app in which I display the object image.
Here is what I've come up with :
def store(url)
#object = Object.find(1)
#object[:image] = CarrierWave::Uploader.store!(image_url)
end
It doesn't seem to work at all.
Any clues?
Is there another way around?
[EDIT]
Here is the current situation :
def store
#object = Object.find(1)
my_uploader = ImageUploader.new
image = open("http://twitpic.com/show/iphone/xxxx.jpg")
# or for a local file:
image = File.open(Rails.root.join('xxxx.png'))
#object[:image] = my_uploader.store!(image)
#object.save!
end
The filename in the [:image] attibute is still wrong. It gives "[:store_versions!]". How do I get the filename right?
[EDIT2]
Got the filename right by adding #artwork[:image] = my_uploader.filename before save.
But #object = Object.find(1) won't work. How do I access the Object class, which is inside my rails app, from the worker?
#object.image.store!(image) finally did the job!
You'll want to create a new uploader object and point it to your file
image = File.open(Rails.root.join('path', 'to', 'file.png'))
#object[:image] = YourUploader.new(image)

What is involved with changing attachment_fu's storage scheme?

I have a rails application that is using attachment_fu. Currently, it is using :file_system for storage, but I want to change it to :s3, to allow for better scaling as more files get uploaded.
What is involved with this? I imagine that if I just switch the code to use :s3, all the old links will be broken. Do I need to just copy the existing files from the file system to S3? A google search hasn't turned up much on the topic.
I would prefer to move the existing files over to S3, so everything is in the same place, but if necessary, the old files can stay where they are, as long as new ones go to S3.
EDIT: So, it is not as simple as copying over the files to S3; the URLs are created using a different scheme. When they are stored in :file_system, the files end up in places like /public/photos/0000/0001/file.name, but the same file in :s3 might end up in 0/1/file.name. I think it is using the id something, and just padding it (or not) with zeros, but I'm not sure of that.
That's correct. The ids are padded using :file_system storage.
Instead of renaming all your files, you can alter the s3 backend module to use padded numbers as well.
Copy the partitioned_path method from file_system_backend.rb and put it in s3_backend.rb.
def partitioned_path(*args)
if respond_to?(:attachment_options) && attachment_options[:partition] == false
args
elsif attachment_options[:uuid_primary_key]
# Primary key is a 128-bit UUID in hex format. Split it into 2 components.
path_id = attachment_path_id.to_s
component1 = path_id[0..15] || "-"
component2 = path_id[16..-1] || "-"
[component1, component2] + args
else
path_id = attachment_path_id
if path_id.is_a?(Integer)
# Primary key is an integer. Split it after padding it with 0.
("%08d" % path_id).scan(/..../) + args
else
# Primary key is a String. Hash it, then split it into 4 components.
hash = Digest::SHA512.hexdigest(path_id.to_s)
[hash[0..31], hash[32..63], hash[64..95], hash[96..127]] + args
end
end
end
Modify s3_backend.rb's full_filename method to use the partitioned_path.
def full_filename(thumbnail = nil)
File.join(base_path, *partitioned_path(thumbnail_name_for(thumbnail)))
end
attachment_fu will now create paths with the same names as it did with the file_system backend, so you can just copy your files over to s3 without renaming everything.
In addition to nilbus' answer, I had to modify s3_backend.rb's base_path method to return an empty string, otherwise it would insert the attachment_path_id twice:
def base_path
return ''
end
What worked for me, in addition to nilbus's answer, was to modify s3_backend.rb's base_path method to still use the path_prefix (which is by default the table name):
def base_path
attachment_options[:path_prefix]
end
And also, I had to take the attachment_path_id from file_system_backend.rb and replace the one in s3_backend.rb, since otherwise partitioned_path always thought my Primary Key was a String:
def attachment_path_id
((respond_to?(:parent_id) && parent_id) || id) || 0
end
Thanks for all those responses which helped a lot. It worked for me too but I had to do this in order to have the :thumbnail_class option working :
def full_filename(thumbnail = nil)
prefix = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
File.join(prefix, *partitioned_path(thumbnail_name_for(thumbnail)))
end

Resources