I have a Rails app A with a postgres database. I also have another Rails app B with a postgres database. Now I want to reuse some of the data of app B in app A. What is the best way to import that data? I assume a rake task can be used for this, but how would you do this?
Do you need to add the connection details of the database of app B in the database.yml of app A? And how do I actually get the data?
You can do a manual connection via activerecord
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "root",
:password => "abcd",
:database => "funonrails")
or do something like this
dbconfig = YAML::load(File.open('database.yml'))
ActiveRecord::Base.establish_connection( dbconfig[:students_development] )
Depending on what you actually mean by import, you could use dblink to query the other DB directly:
http://postgresql.org/docs/current/static/dblink.html
When PostgreSQL 9.3 gets released, be sure to also look into the new foreign data wrapper:
http://postgresql.org/docs/9.3/static/postgres-fdw.html
Related
I'm trying to write a standalone script so I can run a regular cron job that will update the database as well as cache some data to a file locally so we don't have to wait for query times. In doing so, I am using ActiveRecord. I have the following code:
require "active_record"
require "rubygems"
require "./lib/queries/my_query_file"
def my_method
#get stored query string in my_query_file
sql = MY_QUERY
#sql_con = ActiveRecord::Base.establish_connection(
:adapter => "sqlserver",
:host => "my_host",
:port => "my_port",
:username => "my_user",
:password => "my_pass",
:database => "my_db",
:timeout => "100000"
)
##query_result = #sql_con.connection.select_all(sql)
##query_result.each do |row|
#do something
end
end
When I try to run the above script I get the following error:
Specified 'sqlserver' for database adapter, but the gem is not loaded. Add gem '' to your Gemfile. (Gem::LoadError)
Any idea on what the issue could be? I've exhausted my search options to the point where I've gotten a headache from searching for answers. I finally caved in to post a question to see if there are any experts that help or folks that have encountered this issue before that might recall the solution.
You are using :adapter => "sqlserver", which makes ruby assume that sqlserver is the database which you are trying to use. It trying to make a lookup for a ruby gem which has adapter connection for sqlserver.
When we use mysql gem, we can see there are library extensions written in C which help us connect over the ports to current mysql server.
That was kinda lame. I tried what user944938 suggested and that worked. I was just hoping that I can get it to work with ActiveRecord since that is what I am using elsewhere. I updated my code to look like this now:
require "tiny_tds"
require "./lib/queries/my_query_file"
def my_method
sql = MY_QUERY
client = TinyTds::Client.new(
:username => "my_user",
:password => "my_pass",
:host => "my_host",
:database => "my_db"
)
##build_query = client.execute(sql)
##build_query.each do |row|
#do something
end
end
I have a role table with user name and role and company. I want to insert data into that table through a new migration file so how can i do this?
I got a code like this but how can i use it and where i am not able to understand.
class Foo < ActiveRecord::Migration
def self.up
Users.new(:username => "Hello", :role => "Admin")
end
def self.down
Users.delete_all(:username => "Hello")
end
end
This:
Users.new(:username => "Hello", :role => "Admin")
does not insert data into your table. It merely creates a user object. To insert the data you have to call save on the object you create:
Users.new(:username => "Hello", :role => "Admin").save
Or better yet, use create instead of new:
Users.create(:username => "Hello", :role => "Admin")
It appears that you are using this database migration solely for populating the data.
Database migrations are meant for changing the database schema, not for populating the database (though you can add some logic to populate the database after the change; for example, if you add a column - role to users table, you can add some custom logic to populate the newly added field for existing entries in users table). Refer to rails api - migrations for details.
If you forgot add the code to populate the database in your previous database migration, you can undo the previous migration and apply it again using:
rake db:rollback
... Edit the previous migration ..Add the code to populate
rake db:migrate
If you just want to populate the database, you should seed the database instead. Watch this railscast for more information.
EDIT: To seed the database:
Create a file called db/seeds.rb
Add the record creation code like this:
['Sampath', 'Suresh'].each do |name|
User.create(role: 'admin', username: name)
end
Then,
rake db:seed
This will read the seeds.rb and populate the database.
I'm trying to track user login history for stat purposes but its not clear to me what the best way to go about it would be. I could have a separate table that records users and their login stats with a date, but that table could get REALLY big. I could track some historic fields in the User model/object itself in a parse-able field and just update it (them) with some delimited string format. e.g. split on :, get the last one, if an included date code isn't today, add an item (date+count) otherwise increment, then save it back. At least with this second approach it would be easy to remove old items (e.g. only keep 30 days of daily logins, or IPs), as a separate table would require a task to delete old records.
I'm a big fan of instant changes. Tasks are useful, but can complicate things for maintenance reasons.
Anyone have any suggestions? I don't have an external data caching solution up or anything yet. Any pointers are also welcome! (I've been hunting for similar questions and answers)
Thanks!
If you have the :trackable module, I found this the easiest way. In the User model (or whichever model you're authenticating)
def update_tracked_fields!(request)
old_signin = self.last_sign_in_at
super
if self.last_sign_in_at != old_signin
Audit.create :user => self, :action => "login", :ip => self.last_sign_in_ip
end
end
(Inspired by https://github.com/plataformatec/devise/wiki/How-To:-Turn-off-trackable-for-admin-users)
There is a nice way to do that through Devise.
Warden sets up a hook called after_set_user that runs after setting a user. So, supposed you have a model Login containing an ip field, a logged_in_at field and user_id field, you can only create the record using this fields.
Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
Login.create!(:ip => warden.request.ip, :logged_in_at => Time.now, :user_id => record.id)
end
Building upon #user208769's answer, the core Devise::Models::Trackable#update_tracked_fields! method now calls a helper method named update_tracked_fields prior to saving. That means you can use ActiveRecord::Dirty helpers to make it a little simpler:
def update_tracked_fields(request)
super
if last_sign_in_at_changed?
Audit.create(user: self, action: 'login', ip: last_sign_in_ip)
end
end
This can be simplified even further (and be more reliable given validations) if audits is a relationship on your model:
def update_tracked_fields(request)
super
audits.build(action: 'login', ip: last_sign_in_ip) if last_sign_in_at_changed?
end
Devise supports tracking the last signed in date and the last signed in ip address with it's :trackable module. By adding this module to your user model, and then also adding the correct fields to your database, which are:
:sign_in_count, :type => Integer, :default => 0
:current_sign_in_at, :type => Time
:last_sign_in_at, :type => Time
:current_sign_in_ip, :type => String
:last_sign_in_ip, :type => String
You could then override the Devise::SessionsController and it's create action to then save the :last_sign_in_at and :last_sign_in_ip to a separate table in a before_create callback. You should then be able to keep them as long you would like.
Here's an example (scribd_analytics)
create_table 'page_views' do |t|
t.column 'user_id', :integer
t.column 'request_url', :string, :limit => 200
t.column 'session', :string, :limit => 32
t.column 'ip_address', :string, :limit => 16
t.column 'referer', :string, :limit => 200
t.column 'user_agent', :string, :limit => 200
t.column 'created_at', :timestamp
end
Add a whole bunch of indexes, depending on queries
Create a PageView on every request
We used a hand-built SQL query to take out the ActiveRecord overhead on
this
Might try MySQL's 'insert delayed´
Analytics queries are usually hand-coded SQL
Use 'explain select´ to make sure MySQL isusing the indexes you expect
Scales pretty well
BUT analytics queries expensive, can clog upmain DB server
Our solution:
use two DB servers in a master/slave setup
move all the analytics queries to the slave
http://www.scribd.com/doc/49575/Scaling-Rails-Presentation-From-Scribd-Launch
Another option to check is Gattica with Google Analytics
I hate answering my own questions, especially given that you both gave helpful answers. I think answering my question with the approach I took might help others, in combination with your answers.
I've been playing with the Impressionist Gem (the only useful page view Gem since the abandoned RailStat) with good results so far. After setting up the basic migration, I found that the expected usage follows Rail's MVC design very closely. If you add "impressionist" to a Controller, it will go looking for the Model when logging the page view to the database. You can modify this behaviour or just call impressionist yourself in your Controller (or anywhere really) if you're like me and happen to be testing it out on a Controller that doesn't have a Model.
Anyways, I got it working with Devise to track successful logins by overriding the Devise::SessionsController and just calling the impressionist method for the #current_member: (don't forget to check if it's nil! on failed login)
class TestSessionController < Devise::SessionsController
def create
if not #current_member.nil?
impressionist(#current_member)
end
super
end
end
Adding it to other site parts later for some limited analytics is easy to do. The only other thing I had to do was update my routes to use the new TestSessionController for the Devise login route:
post 'login' => 'test_session#create', :as => :member_session
Devise works like normal without having to modify Devise in anyway, and my impressionist DB table is indexed and logging logins. I'll just need a rake task later to trim it weekly or so.
Now I just need to work out how to chart daily logins without having to write a bunch of looping, dirty queries...
There is also 'paper_trail' gem, that allows to track model changes.
I would like to print into log or console the executing sql. Where can I make some settings? In hibernate it is in a config file possibility: I think here should be something like that too.
I have a code part similar to this:
myresult = MyActiveRecordClass.find(:all, :select => "mytable1.*, mytable2.field1", :joins => :mytable2, :conditions => "somefield= #{somefield}", :order => "another_field desc", :offset => offset, :limit => limit)
This is a simpler case to translate by hand, but I would like to have all the native sql in a console or in file. It could be usefully at searching
Rails already displays the SQL in the development log and console (at debug log level - so ensure that the logger is able to display debug log messages).
To also display where in the source code a SQL was called from:
Rails 2: query_trace plugin
Rails 3: Tracing Rails 3 SQL queries (based on query_trace, but works for Rails 3 because query_trace does not currently work on Rails 3)
I would like to see the SQL statement that a given ActiveRecord Query will generate. I recognize I can get this information from the log after the query has been issued, but I'm wondering if there is a method that can be called on and ActiveRecord Query.
For example:
SampleModel.find(:all, :select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")
I would like to open the irb console and tack a method on the end that would show the SQL that this query will generate, but not necessarily execute the query.
Similar to penger's, but works anytime in the console even after classes have been loaded and the logger has been cached:
For Rails 2:
ActiveRecord::Base.connection.instance_variable_set :#logger, Logger.new(STDOUT)
For Rails 3.0.x:
ActiveRecord::Base.logger = Logger.new(STDOUT)
For Rails >= 3.1.0 this is already done by default in consoles. In case it's too noisy and you want to turn it off you can do:
ActiveRecord::Base.logger = nil
Stick a puts query_object.class somewhere to see what type of object your working with, then lookup the docs.
For example, in Rails 3.0, scopes use ActiveRecord::Relation which has a #to_sql method. For example:
class Contact < ActiveRecord::Base
scope :frequently_contacted, where('messages_count > 10000')
end
Then, somewhere you can do:
puts Contact.frequently_contacted.to_sql
just use to_sql method and it'll output the sql query that will be run. it works on an active record relation.
irb(main):033:0> User.limit(10).where(:username => 'banana').to_sql
=> "SELECT "users".* FROM "users" WHERE "users"."username" = 'banana'
LIMIT 10"
when doing find, it won't work, so you'll need to add that id manually to the query or run it using where.
irb(main):037:0* User.where(id: 1).to_sql
=> "SELECT "users".* FROM "users" WHERE "users"."id" = 1"
This may be an old question but I use:
SampleModel.find(:all,
:select => "DISTINCT(*)",
:conditions => ["`date` > #{self.date}"],
:limit=> 1,
:order => '`date`',
:group => "`date`"
).explain
The explain method will give quite a detailed SQL statement on what its going to do
This is what I usually do to get SQL generated in console
-> script/console
Loading development environment (Rails 2.1.2)
>> ActiveRecord::Base.logger = Logger.new STDOUT
>> Event.first
You have to do this when you first start the console, if you do this after you have typed some code, it doesn't seem to work
Can't really take credit for this, found it long time ago from someone's blog and can't remember whose it is.
When last I tried to do this there was no official way to do it. I resorted to using the function that find and its friends use to generate their queries directly. It is private API so there is a huge risk that Rails 3 will totally break it, but for debugging, it is an ok solution.
The method is construct_finder_sql(options) (lib/active_record/base.rb:1681) you will have to use send because it is private.
Edit: construct_finder_sql was removed in Rails 5.1.0.beta1.
Create a .irbrc file in your home directory and paste this in:
if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER')
require 'logger'
RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
end
That will output SQL statements into your irb session as you go.
EDIT: Sorry that will execute the query still, but it's closest I know of.
EDIT: Now with arel, you can build up scopes/methods as long as the object returns ActiveRecord::Relation and call .to_sql on it and it will out put the sql that is going to be executed.
My typical way to see what sql it uses is to introduce a "bug" in the sql, then you'll get an error messages spit out to the normal logger (and web screen) that has the sql in question. No need to find where stdout is going...
Try the show_sql plugin. The plugin enables you to print the SQL without running it
SampleModel.sql(:select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")
You could change the connection's log method to raise an exception, preventing the query from being run.
It's a total hack, but it seems to work for me (Rails 2.2.2, MySQL):
module ActiveRecord
module ConnectionAdapters
class AbstractAdapter
def log_with_raise(sql, name, &block)
puts sql
raise 'aborting select' if caller.any? { |l| l =~ /`select'/ }
log_without_raise(sql, name, &block)
end
alias_method_chain :log, :raise
end
end
end
You can simply use to_sql() function with the active record
Form.where(status:"Active").to_sql
In Rails 3 you can add this line to the config/environments/development.rb
config.active_record.logger = Logger.new(STDOUT)
It will however execute the query. But half got answered :