Creating model with rails - ruby-on-rails

Now, I'm unable to change my db. (many millions rows in each table)
But I would like to create my rails app though.
My DB is absolutely not standard.
Table name : something_people
Fields : stid, stname, stfirstname, stage
I know to change the table_name:
class People < ActiveRecord::Base
self.table_name = "something_people"
end
I would like to rename too the fields. To use the symbol in my rails app and when I'll change the db structure, I only need to change the model classes.
class People < ActiveRecord::Base
self.table_name = "something_people"
self.field_name(:id) = "stid"
self.field_name(:name) = "stname"
self.field_name(:firstname) = "stfirstname"
self.field_name(:age) = "stage"
end
an example of query :
#countid = People.where(hash_of_conds).count(:id)
is
SELECT COUNT(stid) FROM something_people WHERE myconditions;
Asked question : How to do what I want to do ?
If you don't understand, tell me.
Thank you.

you can create aliases
class User < Activerecord::Base
alias_attribute :id, :stid
alias_attribute :name, :stname
end
But when you have a query like this
User.where("stname like '%ab%'")
you will have to specify the actual column name in the database

Related

ruby on rails migrations using an existing table

I have this problem. I need to use an existing table on a mysql database. The name of the table is not compatible with RoR conventions and I need to remap the table name and the name of the attributes. I have created a scaffold to visualize on a web page the content of the table but I can't change the mapping. Is there a solution to indicate to RoR the relation between the name of the class and the name of the table in the database? and a solution to indicate the relation between the attribute of the class and field on the table?
Thanks.
The table name can be specified using table_name class method.
For the attributes/column, you need to explicitly specify aliases for the attributes using alias_attribute method. For example, if you have name_of_thing column, but want to treat it as name, then you need something like this in your model:
class CreateUtenti < ActiveRecord::Base
self.table_name = "another_name"
alias_attribute :name, :name_of_thing
end
Yes you can pass table name in model like:
class YourModel < ActiveRecord::Base
self.table_name = "pass_table_name_here"
end

Rails how to find id by another attr in a callback model?

I'm looking to create a callback where update a object if find the id attribute of another model.
in this case if find update Odata model if find the order_id.
someone know how to find the object based on another model id attribute?
class Order < ActiveRecord::Base
after_update :update_odata
def update_odata
order = Order.find_by_id(attributes['id'])
od = Odata.find_by_id(attributes['order_id'])
od.shipping_cost = order.shipping_cost
od.shipping_method = order.shipping_method
od.status = order.status
od.feedback_id = order.feedback_id
od.track_number = order.track_number
od.seller_name = order.seller_name
od.buyer_name = order.buyer_name
od.save
end
end
In general you should check the docs and at least make an effort to learn the tools you're using before resorting to asking for someone to help explain it to you on StackOverflow.
To answer your question, find(1) is effectively a shortcut method for find_by(id: 1). Thusly, if you want to find an order by customer_id you could do this: Order.find_by(customer_id: 42).
Or, if you're trying to make this contingent on order (making some assumptions based on how Rails apps are built vs this unusual attributes stuff you have in your example):
order = Order.find(params[:id])
od = Odata.find_by(order_id: order.id)
In which case, you should probably just use relations:
class Order < ApplicationRecord
has_one :odata
end
class Odata < ApplicationRecord
belongs_to :order
end
# controller:
order = Order.find params[:id]
od = order.odata
If you wanted to do exactly what you are above, which is probably a bad path to go down, you would probably want to do something like this:
class Order < ApplicationRecord
has_one :odata
def attributes_for_odata
%w{ shipping_cost shipping_method status feedback_id track_number seller_name buyer_name }
end
def update_order_data
odata.update attributes.slice(*attributes_for_odata)
end
end

Associate two already existing objects using Has And Belongs To Many

I'm making an App in Rails to show anime, these animes has and belongs to many languages, so I made a HABTM association:
class Anime < ActiveRecord::Base
has_and_belongs_to_many :languages
end
class Language < ActiveRecord::Base
has_and_belongs_to_many :animes
end
Now I don't know how can I make associations between them, I've created many Languages' records to use them, for example, Language with ID 1 is English, Language with ID 2 is Spanish, etc... And I want to just make the associations between an anime and a language, ie, if I want to say that the Anime with ID 1 it's available in Spanish only, then in the table animes_languages I want to create the record with values anime_id: 1 and language_id: 2 and nothing more, but I belive that if I execute the command Anime.find(1).languages.create it will not use an already existing language, it will create a new language, but the only thing I want is to make associations between already existing animes with already existing languages, so, How can I do this? Should I make a model for the table animes_language?
It's confusing for me cause when I created that table as specified here enter link description here, I created the table without ID, it only have the fields anime_id and language_id.
Just to be safe I will back it up.
First you migrate your tables to remove already existing association to one or the other reference (i.e. if language already have many animes, etc).
Then you need to create a migration to create the associative table.
rails g migration CreateJoinTableAnimeLanguage anime language
Then the association pointers in your models should work properly.
class Anime < ActiveRecord::Base
has_and_belongs_to_many :languages
end
class Language < ActiveRecord::Base
has_and_belongs_to_many :animes
end
At which point whenever you want to associate one to the other already existing:
Anime.find(1).languages << Language.find(1)
Experience would recommend against trying to do this in seperate steps.
I'd say find what gets created the most, I'd guess Anime, then find a way to choose or create a language using:
class AnimeController < ApplicationController
def create
#anime = Anime.new(anime_params)
#success = #anime.save
end
private
def anime_params
params.require(:anime).permit(:stuff, :languages => [:id, :or_stuff])
end
end
Should be as simple as
anime = Anime.find(1)
language = Language.find(1)
anime.languages << language
And that will create the join record in between the two

Parse nested JSON and save it to the database with rails

Using rails (4), I would like to parse some data from an external API and store it into my database. For instance:
{ "name" : "Mercedes-Benz",
"commonName: "Mercedes",
"vehicles" : [ {
"name" : "Mercedes c5",
"components" : ["wheels", "doors"]
}]
}
I am aware that with JSON.parse I could create a new instance and store it if the json would match, but there are a few problems that prevent me to do it:
commonName uses cammelcase instead of rails typical underscore. Is there a way i can magically assign a key to an attribute?
Will vehicles be saved to the table vehicles ? Can I accomplish that automatically? Or should I go through every vehicle and save each one?
Components is just an array of strings. What would be a good way to represent that? Just another table with an attribute name?
Yes, if you want to be able to look up the components then having it as a separate table makes sense. It would need a vehicle_id as well as name.
For accepting the attributes for the vehicles and components use accepts_nested_attributes_for.
So your models should looked something like this:
class VehicleType < ActiveRecord::Base
has_many :vehicles
accepts_nested_attributes_for :vehicles
end
class Vehicle < ActiveRecord::Base
belongs_to :vehicle_type
has_many :components
accepts_nested_attributes_for :components
end
class Component < ActiveRecord::Base
belongs_to :vehicle
end
For converting commonName (camelCase) to common_name (snake case), there's a great Stack Overflow answer on that here: Converting nested hash keys from CamelCase to snake_case in Ruby. So assuming you have defined the function described there (convert_hash_keys) and the models above, your code should look roughly like this:
converted_hash = convert_hash_keys(JSON.parse(input_json_string))
vehicle_type = VehicleType.create(converted_hash)
For updating it would be VehicleType.update(converted_hash)

Active Record joined-grouped query on PostgreSQL

I am working on a rails project for a while and I juste encountered (what I think is) a small problem.
To make it simple, I have 3 model like this:
class House < ActiveRecord::Base
has_many :house_style_relationships
end
class HouseStyleRelationship < ActiveRecord::Base
attr_accessible :percentage
belongs_to :style
belongs_to :house
end
class Style < ActiveRecord::Base
has_many :house_style_relationships
end
So the HouseStyleRelationship model simply let us know the style percentage of an House.
For example an House can be 70% Modern and 30% Classic.
What I need to do is to get the average of each styles for all the houses.
To do that I used this working query under SQLite:
houses_count = Houses.count
HouseStyleRelationship.joins(:style).select("style.name, SUM(house_style_relationships.percentage)/#{houses_count} as percentage").group("styles.id")
But when I decided to push all this stuff on Heroku, I got a problem with PostgreSQL.
In fact, to create an HouseStyleRelationship object (I don't even need), ActiveRecord ask for a HouseStyleRelationship.id which make the Group By crashing (with the query).
(PostgreSQL don't want to group records with different ids)
Do you have a solution to prevent ActiveRecord to generate model instances as answer and so remove the HouseStyleRelationship.id from the query ?
(I can't use SELECT DISTINCT since I need the SUM() calculation)
Thanks in advance !
You need to create your join table such that it has no primary key. The create_table statement in your migration should look something like this.
create_table :houses_style_relationships, :id => false do |t|

Resources