I have an app that I've converted over from another cms. The old URLs were being stored in the database like so:
/this-is-an-old-permalink/
And I need them to be like this:
this-is-an-old-permalink
Note the absence of forward slashes. What is the easiest way to go about removing them?
I'm not necessarily looking for the exact code to do it (although that'd be nice!) -- I'm asking also as a Rails newb: What is the best method to go about doing things like this? I've only really worked with Rails in setting up a model, controller, views and outputting data. I haven't had to do any processing like this. Would it go in the model? Any help is appreciated!
edit
Do I need to get all records, loop through them, do regex on that one field and then save it?
Since you're likely only going to write this once, your best bet is to create a script for it within lib, or to write a migration for it. I recommend the latter, because it will then be executed automatically with rake db:migrate if you restore from your old backup at a later date. You can then use all your standard Model processing tricks (like you would use on a Controller) within the migration without exposing the substitution code to a Controller.
EDIT:
You can add the following to a new file within lib/tasks to create a new rake task for this called db:substitute_slashes:
namespace :db do
desc "Remove slashes from old-style URLs"
task :substitute_slashes => :environment do
Modelname.find(:all).each do |obj|
obj.fieldname.gsub!(/regex here/,'')
obj.save!
end
end
end
The exclamation on the end of save! means it will throw an exception if the resulting object fails validation, which is a good thing to check for in this case.
You would then be able to execute this with the command rake db:substitute_slashes.
Related
I am adding thousands of entries to my database through seeds.rb and a CSV file. In order to do so I am using Fast_Seeder:
FastSeeder.seed_csv!(Artist, "artist_sample.csv", :name, :sort_name)
I use Friendly-id, and as it is now, it is not creating a slug because I am not feeding it through the file.
How do I go about creating it without having to change the file manually?
Any help would be much appreciated!
I'm not familiar with Fast_Seeder, but I am with friendly-id. Their docs say the following:
# If you're adding FriendlyId to an existing app and need
# to generate slugs for existing users, do this from the
# console, runner, or add a Rake task:
User.find_each(&:save)
It would obviously be more efficient to get friendly-id playing nice in the first place, but barring that you can add that the next line. You basically just need to tap validation. I bet .find_each(&:valid?) might work too. This leads me to wonder if FastSeeder is creating these records without hitting your validations.
EDIT: Yup, I just dug through their source and they are creating straight through the database. You'll probably need to go the route I outlined above.
Just learning rails, am on to migrations and it all started off pretty logically until I hit something odd going on in the code;
rails generate migration AddRegionToSupplier
The above produces a migration file with only a "def change" method in it.
I googled this and found that this is exactly what is supposed to happen;
http://guides.rubyonrails.org/migrations.html
I would have expected it to generate a "def up" and "def down" method, so that the migration could be rolled back. Have I done something wrong in the generation or am I missing something obvious?
From the link you pasted:
Rails 3.1 makes migrations smarter by providing a new change method.
This method is preferred for writing constructive migrations (adding
columns or tables). The migration knows how to migrate your database
and reverse it when the migration is rolled back without the need to
write a separate down method.
So it looks like you don't have to worry about having a def self.down as Rails is now smart enough to know how to roll it back.
EDIT: I have totally rewritten this question for clarity. I got no comments and no answers earlier.
I am maintaining a 2.x Rails app with plenty of statistical data. Some data is real and some is estimated for the future years. Every year I need to update estimated data with real data and calculate new estimates.
I have been using BIG yml-files and migrations for loading the data into the app every year. My migrations are full of estimation calculations and data corrections.
Problem
My migrations are full of none-schema related material and I can't even dream of doing db:migrate:reset without waiting few hours (if it even works). I'd love to see my migrations nice and clean - only with schema related modifications. But how I am suppose to update the data every year if not using migrations?
Help needed
I'd like to hear your comments and answers. I'm not looking for a silver bullet - more like best practises and ideas how people are handling similar situation.
It sounds like you have a large operation (data load using yml files) once a year but smaller operations once a month.
From my experience with statistical data you will probably end up doing more and more of these operations to clean and add more data.
I would use a job processing framework like resque and resque scheduler.
You can schedule the jobs to run once a month, year, day or constantly running. A job is something like loading yml files (or sets of yml files) or cleaning up data. You can control parameters to send to your job so you can use one class but alternate how it updates or cleans your data based on the way you enqueue or schedule the job.
First of all, I have to say that this is a very interesting question. As far as i know, it isn't a good idea loading data from migrations. Generally speaking you should use db/seeds.rb for data loading in your db and I think it could be a good idea to write a little class helper to put in your lib dir and then call it from db/seeds.rb. I image you could organize you files in the following way:
lib/data_loader.rb
lib/years/2009.rb
lib/years/2010.rb
Obviously, you should clear your migrations and write code for lib/data_loader.rb in the way you should prefer but I was only trying to offer a general idea of how I'd organize my code if I have to face a problem like that.
I'm not sure I've replied to your question in a way that helps but I hope it does.
If I were you I would go with creating custom rake task. You will have access to all you models and activerecord connections and once a year you will end up doing:
rake calculate
I have a situation where I need to load data from CSV files that change infrequently and update data from the Internet daily. I'll include a somewhat complete example on how to do the former.
First I have a rake file in lib/tasks/update.rake:
require 'update/from_csv_files.rb'
namespace :update do
task :csvfiles => :environment do
Dir.glob('db/static_data/*.csv') do |file|
Update::FromCsvFiles.load(file)
end
end
end
The => :environment means we will have access to the database via the usual models.
Then I have code in the lib/update/from_csv_files.rb file to do the actual work:
require 'csv'
module Update
module FromCsvFiles
def FromCsvFiles.load(file)
csv = CSV.open(file, 'r')
csv.each do |row|
id = row[0]
s = Statistic.find_by_id(id)
if (s.nil?)
s = Statistic.new
s.id= id
end
s.survey_area = row[1]
s.nr_of_space_men = row[2]
s.save
end
end
end
end
Then I can just run rake update:csvfiles whenever my CSV files changes to load the new data. I also have another task that is set up in a similar way to update my daily data.
In your case you should be able to write some code to load your YML files or make your calculations directly. To handle your smaller corrections you could make a generic method for loading YML files and call it with specific files from the rake task. That way you only need to include the YML file and update the rake file with a new task. To handle execution order you can make a rake task that calls the other rake tasks in the appropriate order. I'm just throwing around some ideas now, you know better than me.
I have a bunch of rails models that I'm re-writing into a single model to simplify my code and reduce unnecessary tables.
I'm wondering what the best way to delete a model class and its table is. I want past migrations to still succeed, but I don't want to leave the empty models lying around.
Do I have to manually delete the old migrations that reference these models, then manually delete the class files?
Does anyone have any tips for the best way to do this?
All in one solution.
Run the following commands:
rails destroy model ModelName
rails g migration DropTableModelName
The former will generate a new migration file which should looks like this:
class DropTableModelName < ActiveRecord::Migration
def change
drop_table :model_name
end
end
Now run db:migrate and you're done.
If you'd like to completely get rid of of a model and its table do this:
rails destroy model Name
The question is a bit stale now, but I just did:
rails destroy scaffold <ModelName> -p
The -p flag shows "pretend" output, which is good for seeing what will happen. Remove the '-p' flag and the results will match the output. This cleaned the entire collection of M-V-C files + testing + js files + the original migration, no problem.
I guess if you are one who likes to hand edit your migrations and include multiple steps in each, losing the original migration could break db:setup, so buyer beware. Keeping one action == one migration file should avoid this potential snafu.
What about doing ruby script/destroy model? That should take care of the model and the migration.
Depending on how far into development or production you are, you may want to migrate the models out safely using a migration to remove/backup data or what not. Then as bobbywilson0 suggested, using
script/destroy model
or if you rspec anything
script/destroy rspec_model
This will remove any spec tests as well.
Or you can always just drag them to the trash folder.
You can take a look at this one at rails guide.
But I suggest, if it is possible, you should delete the models and all references to the models. This will probably save time later as you don't need to maintain the dead code in the codebase.
If you'd rather have a manual based answer:
First run the following command to identify which migrations you want removed:
rake db:migrate:status
Feel free to grep -i on it too if you're confident of your naming scheme.
Make note of all the "add x to model name" and similar alterations to your Model. These can be removed using:
rails d migration AddXToModelName
Do this for every migration besides the initial create migration. The following command will take care of the initial create migration and the files associated with the model:
rails d model ModelName
I am developing an app that needs to send text messages, so I have carrier information stored in a database. I also need that information in an XML file for client side code to read. To make this happen, I am writing a script that reads the carrier information from the DB and creates an XML file in the config directory. I felt this script would fit best in lib/tasks.
I need to access the database from this script, but I want to use some object to access it. If I use
db = Mysql.new("domain", "username", "password", "database")
I will have to keep multiple versions for different environments because I do not use MySQL all the time. That would be very sloppy. I am sure there is a way to do this. I tried to just access the object...this is what I have so far:
RAILS_HOME = File.expand_path(File.join(File.dirname(__FILE__),"../.."))
RAILS_CONFIG = "#{RAILS_HOME}/config"
f = File.new("#{RAILS_CONFIG}/mls_widget_config.xml", "w")
carriers = Carrier.find_all
f.write carriers
f.close
But Carrier is not defined, which makes sense. How can I give this script access to the the Carrier object in the DB?
Also as a side, if anyone knows how to easily convert what I read from the DB into proper XML that would be great. I was going to write something custom real quick.
Thank you!
You can enable a Rake task to access your models by defining your task like this:
task :my_task => :environment do
# Task code
end
Note the => :environment, which grants this access. You can then instruct your Rake task to use different environments this way:
rake RAILS_ENV=development my_task
rake RAILS_ENV=production my_task
As for XML serialization, you can use the built-in to_xml method, such as:
Carrier.all.to_xml
Note that the method .all is a recent addition to Rails, and is an alias for .find(:all).
You're actually almost there; I'd just recommend requiring your Rails environment as part of the script, like so:
RAILS_HOME = File.expand_path(File.join(File.dirname(__FILE__),"../.."))
RAILS_CONFIG = "#{RAILS_HOME}/config"
require "#{RAILS_CONFIG}/environment"
Now you should have access to all of your domain structure. Rails also includes default XML serialization through the use of the to_xml method call; try Carrier.find(:all).to_xml.
By convention, lib/tasks is usually reserved for rake tasks - you might want to put your library code in its own directory. lib/messaging, maybe?
Are you running an old version of Rails? find_all doesn't work in recent versions: 'find(:all)' or just 'all' are the methods nowadays.
File.new("#{RAILS_ROOT}/mls_widget_config.xml", "w") do |f|
Carrier.all.each { |carrier| f.puts carrier.to_xml }
end