Need to change relation between DB tables - mysql

ok, so lets get the basics out of the way.
I'm running ruby 1.8.7, I'm using the sequel gem version '2.6.0'.
I have a table called Users and a table called Teams
Right now a user can have one team and as such it's relation is:
belongs_to :npt_team
However as part of a feature upgrade for teams I have to make it so Users can be apart of multiple teams.
What I want to know:
I can change it to one of the following:
:has_and_belongs_to_many
:many_to_many
:many_to_many_by_ids
which one is the best to use and why(because I like to know)?
Second of all what will happen to the DB in the tables when I change this?
Any thing else I should be wary of/know about?
I'm using the following mysql version:
mysql Ver 14.14 Distrib 5.6.29, for osx10.11 (x86_64) using EditLine
wrapper
EDIT:
Ooops forgot to mention a rather pertinent point.
I'm not using rails, I'm use an old frame work called Ramaze.

The answer to my question is:
to create the relationship I need to add the following to the Users table:
has_and_belongs_to_many(:npt_teams,
:join_table => :users_teams,
:class => 'NptTeam',
:left_key => :user_id,
:right_key => :npt_team_id)
many_to_many_by_ids :npt_teams, 'UsersTeams'
Create a new join table like so:
class UsersTeams < Sequel::Model
clear_all
set_schema {
primary_key :id
integer :user_id, :null => false, :default => 0
integer :npt_team_id, :null => false, :default => 0
}
create_table unless table_exists?
belongs_to :user
belongs_to :npt_team
end
and the relationship is created along with the join table.
I don't know if this is the best way to do it but It seems to work.
As for the second question, I don't know, the data currently in the DB seems to be unaffected.
Now I just need to move the current Team to the new table and that should be it.
As for what else I might need to know well I don't, becuase you know, those that do know have seen to know have not respond so I'm just going to have to wing it.
EDIT:
script to move data across:
User.all.each do |user|
join = UsersTeams.create(:user_id => user.id, :npt_team_id => user.npt_team_id)
puts join.inspect
join.save
puts user.npt_teams.to_a.map {|t|t.inspect}.to_s
end

Related

Rails + Postgres Relation Issue With Custom Foreign Key

I'm in the middle of a migration to Postgres from MySQL and i'v hit an issue that I just can't solve. I'm sure there is simple answer, but i'm stuck.
The Problem
I have a step model that belongs to a template model, but specifies a foreign key called template_uuid to match on the template tables uuid column.
This all worked fine on MySQL but now does not work on Postgres. Calling step.template would return the relevant template but now it returns nil
Both the uuid column on the template table and the template_uuid column on the step are UUID data types.
Example:
class Step < ActiveRecord::Base
belongs_to :template, :foreign_key => :template_uuid
So, I get nil when trying to call the association
step = Step.last
step.template => nil
But, I can query for the template using the template_uuid column, and it works just fine
Template.where(:uuid => step.template_uuid).first
So .. What am I missing here. The records and UUID's clearly line up so why does this relationship break now that i'm using Postgres. There is no physical foreign key on the database, but that's never mattered before.
Does anyone have any ideas?
I can't say why it worked before, but as long as you have also a custom primary_key on the associated model (other than :id), you have to provide that either
belongs_to :template, :primary_key => :uuid, :foreign_key => :template_uuid

What is the easiest way to insert data in MySQL using a ruby script

I did a ruby script that parses a lot of files in ruby data structures, like hashes for example.
I need to insert all this data in a MySQL database.
What I found:
mysql2
tmtm
dbi
Is there some native way to do this?
Thanks for any help
EDIT
Lets say that I have a hash with 100 entries like this:
hash = {"a" => 1, "b" => 2 ..., "c" => 100}
I would like to create a table at mysql with all this columns. I am afraid of Active Record is gonna be hard to do that.
PS: Im not using Rails, just a simple ruby script
If I were you, I would prefer ActiveRecord, because I don't have to clutter my code with lots of SQL statements. Besides activerecord makes life easier.
Set it up like this
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:host => "host",
:username=>"user",
:password=>"user",
:database => "your_db"
)
Then use tables like this
class SingularTableName < ActiveRecord::Base
has_many :table_relationship
end
Then query like this
SingularTableName.all #=> all records
SingularTableName.first #=> first record
SingularTableName.where("query")
SingularTableName.create("...) #=> create a record/row
You can find more methods here => http://api.rubyonrails.org/classes/ActiveRecord/Base.html
Update:
To overcome plural table names and default primary key, you can use
class AnyName < ActiveRecord::Base
self.table_name = 'your table name'
self.primary_key = 'your primary key'
...
end

Rails: Selecting from multiple tables using .join()

Plugins Model:
class Plugin < ActiveRecord::Base
belongs_to :report
has_many :vulns
end
Vulns Model:
class Vuln < ActiveRecord::Base
belongs_to :plugins
end
I'm doing the following in rails:
#using * for now to select everything
#data = Plugin.select("*").joins(:vulns).where('plugins.id'=> plugin.plugin_id)
Which does the following query in the terminal:
SELECT * FROM `plugins` INNER JOIN `vulns` ON `vulns`.`plugin_id` = `plugins`.`id` WHERE `plugins`.`id` = 186
It's the right query but it doesn't select the content from the vulns table. I know it's the right query because I tried it in phpmyadmin and it returned the data on the vulns table too. When I do it in rails (using <%= debug(#data) %>) it only shows content from the plugins table.
How do I make it select everything from the vulns table too? (Each plugin has multiple vulns)
Apparently you can't have a column with the name "type".
If anybody has similar issues, rename the column called "type". I generated a new migration:
rails g migration RenameColumnOnVulnsTable
And then added the following:
def change
rename_column :vulns, :type, :vulnerability_type
end
The query works fine now.

Thinking Sphinx "no field found in schema" error

I am pretty new to Sphinx.
Trying to find user with name "bob" and company_id "14".
Controller:
#users = User.search 'bob', :conditions => { :company_id => '14'}
Model:
define_index do
indexes :name
indexes :company_id
end
Error:
index user_core: query error: no field 'company_id' found in schema
I have the 'company_id' in table & I re-indexed everything several times.
When I am just searching for the 'name' everything works properly.
Just as another helpful hint: turns out I had to change the way I called Model.search(), since my field was listed as an attribute (i.e. using has), I needed to call the search method with :with instead of :conditions (for fields).
Attributes should be declared as:
has company_id
So, in you case:
Model:
define_index do
indexes :name
has :company_id
end
And one more helpful hint, if you happen to be an idiot like me:
If you are getting this error and you are correctly using attributes and fields, it may be that you forgot to restart your dev server after adding a new field to the index.

How to seed Devise users efficiently?

I'm trying to seed about 100,000 users using rake db:seed in my Rails 3 project and it is really slow!
Here's the code sample:
# ...
User.create!(
:display_name => "#{title} #{name} #{surname}",
:email => "#{name}.#{surname}_#{num}#localtinkers.com",
:password => '12341234'
)
It works, but it is really slow because for each user:
Devise issues a SELECT statement to find out if the email is already taken.
A separate INSERT statement is issued.
For other objects I use "ar-extensions" and "activerecord-import" gems as follows:
tags.each do |tag|
all_tags << Tag.new(:name => tag)
end
Tag.import(all_tags, :validate => false, :ignore => true)
The above creates just one INSERT statement for all the tags and it works really fast, just like MySql database restore from the SQL dump.
But for users I cannot do this because I need Devise to generate encrypted password, salt, etc for each user. Is there a way to generate them on the SQL side or are there other efficient ways of seeding users?
Thank you.
How about:
u = User.new(
:display_name => "#{title} #{name} #{surname}",
:email => "#{name}.#{surname}_#{num}#localtinkers.com",
:password => '12341234'
)
u.save!(:validate => false)
This should create and save the record without executing the validations, and therefore without checking for e-mail address uniqueness. Obviously the downside of this is that you're not being protected by any other validations on the user too, so make sure you check your data first!