How to make selection content an attribute for a Rails model - ruby-on-rails

I am having a hard time even formulating the question I want to be answered, so here's my situation:
I'm trying to make a simple stock market plotter tool using an existing database I populate elsewhere. My app already has a nice and dynamic plotter that works with any database, but it expects data in a certain way. So say my model (database) looks like this:
Stock:
|___ticker___|___open___|___close___|___date___|
| aapl | 100 | 101 | 1/1/11 |
| aapl | 101 | 102 | 1/2/11 |
| goog | 500 | 450 | 1/1/11 |
| goog | 450 | 451 | 1/2/11 |
...
My plotter routines work off of class attributes (I think thats the terminology), which correspond to columns in the database.
I can select all the data corresponding to 'aapl', and easily plot the open and close versus date since my model has said attributues.
#stock = Stock.select_by_ticker('aapl')
>> #stock.open #=> 100 ...
>> #stock.close #=> 101 ...
>> #stock.date #= 1/1/11 ...
so the attributes would be
{open, close, date}
But if I want to compare say the closing price for different stocks, I need attributes pertaining to each stock. So basically I want to end up with a model with ticker names as attributes, each corresponding to that ticker's hunk in the database. Using easy to build scopes, I want something like:
#stock = Stock.select_close_by_ticker('aapl','goog')
attributes are:
{aapl, goog, date}
where aapl and goog contain the closing price data for just that ticker. I can run multiple database queries if I need to, for now I just want to be able to sort my data into this form. Also, it must be completely dynamic, so I can't hardcode 'aapl', 'goog' and all the millions of other tickers into my model.

Would something like:
stocks = ['appl', 'goog']
Stock.find(:conditions => ['ticker in (?)'], stocks)
work for your scenario?

Related

Rails using Views instead of Tables

I need to create a Rails app that will show/utilize our current CRM system data. The thing is - I could just take Rails and use current DB as backend, but the table names and column names are the exact opposite Rails use.
Table names:
+-------------+----------------+--------------+
| Resource | Expected table | Actual table |
+-------------+----------------+--------------+
| Invoice | invoices | Invoice |
| InvoiceItem | invoice_items | InvItem |
+-------------+----------------+--------------+
Column names:
+-------------+-----------------+---------------+
| Property | Expected column | Actual column |
+-------------+-----------------+---------------+
| ID | id | IniId |
| Invoice ID | invoice_id | IniInvId |
+-------------+-----------------+---------------+
I figured I could use Views to:
Normalize all table names
Normalize all column names
Make it possible to not use column aliases
Make it possible to use scaffolding
But there's a big but:
Doing it on a database level, Rails will probably not be able to build SQL properly
App will probably be read-only, unless I don't use Views and create a different DB instead and sync them eventually
Those disadvantages are probably even worse when you compare it to just plain aliasing.
And so I ask - is Rails able to somehow transparently know the id column is in fact id, but is InvId in the database and vice versa? I'm talking about complete abstraction - simple aliases just don't cut it when using joins etc. as you still need to use the actual DB name.

rails user-defined custom columns

I am using Ruby on Rails 4 and MySQL. I have three types. One is Biology, one is Chemistry, and another is Physics. Each type has unique fields. So I created three tables in database, each with unique column names. However, the unique column names may not be known before hand. It will be required for the user to create the column names associated with each type. I don't want to create a serialized hash, because that can become messy. I notice some other systems enable users to create user-defined columns named like column1, column2, etc.
How can I achieve these custom columns in Ruby on Rails and MySQL and still maintain all the ActiveRecord capabilities, e.g. validation, etc?
Well you don't have much options, your best solution is using NO SQL database (at least for those classes).
Lets see how can you work around using SQL. You can have a base Course model with a has_many :attributes association. In which a attribute is just a combination of a key and a value.
# attributes table
| id | key | value |
| 10 | "column1" | "value" |
| 11 | "column1" | "value" |
| 12 | "column1" | "value" |
Its going to be difficult to determin datatypes and queries covering multiple attributes at the same time.

Dynamic categories criteria with matching products rails 3

I'm working on a new rails project, and in this project I have products and product categories.
So these categories are very different from each other, to name some, Boats, Houses, Cars.
The car category might have criterias like "Mph", "Model", "Brand", "Year" and so on. Where the house category will have something like "Rooms", "Year", "City", "Postal Code" etc.
I would like this to be very dynamic, so that i would be able to add/remove criterias and add/remove categories from a backend panel.
Now to my question, i have been playing around with this, and i can't really figure out the logic of this concept, i have tried some solutions, however they are very weird and quite inefficient. Maybe some hardcore rails coder could give me a hint, on how to solve this puzzle?
So the best solution i could come up with, was this:
Four models :
_______________________
| Product.rb |
-----------------------
| id | integer |
-----------------------
| category_id | integer |
-----------------------
| Title | string |
-----------------------
| Description | text |
-----------------------
_______________________
| Category.rb |
-----------------------
| id | integer |
-----------------------
| Title | string |
-----------------------
| Description | text |
-----------------------
_______________________
| Criteria.rb |
-----------------------
| id | integer |
-----------------------
| category_id | integer |
-----------------------
| Name | string |
-----------------------
| Default | string |
-----------------------
| Description | text |
-----------------------
_______________________
| ProductInfo.rb |
-----------------------
| id | integer |
-----------------------
| product_id | integer |
-----------------------
| Name | string |
-----------------------
| Value | text |
-----------------------
How it's connected :
Criteria.rb is connected to Category.rb with a category_id and has_many/belongs_to relation
Product.rb is connected to Category.rb with a category_id and has_many/belongs_to relation
ProductInfo.rb is connected to Product.rb with a product_id and has_many/belongs_to relation.
Category.rb is the heart og this solution. The category model, both have many products and criterias.
How it should work, in reality :
In the show category page, i would first print out all the criterias for the given category.
Afterwards i would make a #products.each do |product|.
In the #products.each block, i would make a #category.criterias.each do |criteria|.
In the #category.criterias.each block, i would then run something like product.productinfos.where(:name => criteria.name).
And then run it one by one.
Conclusion, this solution do work, however i doubt that it is the best solution. It will make an extremely big loadtime, with high traffic and many data. And i will need to write very weird and unreadable code.
This is a rather long question, and it might be very confusing, so if there is anything please just say. Also, i have searched quite alot for a question like this, both on Stackoverflow, and on google but i have not been able to find anything like this.
Oluf Nielsen.
In my opinion, it's better not to define additional tables to handle this due lots of performance issues. My preference to handle such things is to use a serialized column in the products table. Ability to search directly in the database is reduced with this approach, but then you wouldn't want to do that anyway. To handle search, you have to add some sort of indexed searching mechanism. Like acts_as_ferret or even Solr or ElasticSearch.
If you are using postgres check out https://github.com/softa/activerecord-postgres-hstore
For Mysql, use the rails's built in 'store'
http://api.rubyonrails.org/classes/ActiveRecord/Store.html
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
store :settings
end
To set criteria for each category do something similar to this:
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
def criteria
#criteria_list ||= self[:criteria].split('|')
#criteria_list
end
def criteria=(names)
self[:criteria] = names.join('|')
end
end
Everytime a product is added to a category, check if all of the criteria in that category is available in the product's properties hash keys. If not, add it with a default value if needed.
You can also setup accessors for the properties hash store using a proc that dynamically gets the accessor names from the all the criteria field of the categories of the product? (not sure about this, cause I haven't done this before)
You can also look into using STI (Single table Inheritance) using a type field in your products table. (It's well documented) This approach is slightly better 'cause when products move from one category to another, the properties won't change.
class Gadget < Product
store_accessor :manufacturer, :model
end
class Phone < Gadget
store_accessor :os, :touch_screen, :is_smart
end
Hope this helps
Or else, second approach would be go with a nosql database. Try mogodb with mongoid, which is quite stable. This will suite your requirements for variable attributes very well. Also you can add any other categories later with very ease.
As far as I can see, with mysql, you will end up creating multiple dbs for storing this dynamics data and that is bound hamper the performance.
UPDATE -
Apart from the point that your data can be flexible with nosql, there are many things you need to consider before shifting there. I just suggested based on fact that you need flexible database structure. Start with mogodb docs, they are good starting point.

Cassandra cql kind of multiget

i want to make a query for two column families at once... I'm using the cassandra-cql gem for rails and my column families are:
users
following
followers
user_count
message_count
messages
Now i want to get all messages from the people a user is following. Is there a kind of multiget with cassandra-cql or is there any other possibility by changing the datamodel to get this kind of data?
I would call your current data model a traditional entity/relational design. This would make sense to use with an SQL database. When you have a relational database you rely on joins to build your views that span multiple entities.
Cassandra does not have any ability to perform joins. So instead of modeling your data based on your entities and relations, you should model it based on how you intend to query it. For your example of 'all messages from the people a user is following' you might have a column family where the rowkey is the userid and the columns are all the messages from the people that user follows (where the column name is a timestamp+userid and the value is the message):
RowKey Columns
-------------------------------------------------------------------
| | TimeStamp0:UserA | TimeStamp1:UserB | TimeStamp2:UserA |
| UserID |------------------|------------------|------------------|
| | Message | Message | Message |
-------------------------------------------------------------------
You would probably also want a column family with all the messages a specific user has written (I'm assuming that the message is broadcast to all users instead of being addressed to one particular user):
RowKey Columns
--------------------------------------------------------
| | TimeStamp0 | TimeStamp1 | TimeStamp2 |
| UserID |------------|------------|-------------------|
| | Message | Message | Message |
--------------------------------------------------------
Now when you create a new message you will need to insert it multiple places. But when you need to list all messages from people a user is following you only need to fetch from one row (which is fast).
Obviously if you support updating or deleting messages you will need to do that everywhere that there is a copy of the message. You will also need to consider what should happen when a user follows or unfollows someone. There are multiple solutions to this problem and your solution will depend on how you want your application to behave.

find_by_sql not working on rails 3.1.3

I am writing a quite complex query in Ruby on Rails 3.1.3, and I am using find_by_sql.
But I noticed a very strange behaviour, even if I use find_by_sql with very simple queries.
Here is a simple example:
Let' say that I have two models and related tables:
Model 1: Company
Table 1: companies
fields: id, name, address
| id | name | address |
+----+------+-----------------+
| 1 | ACME | Bond street, 56 |
and:
Model 2: Employee
Table 2: employees
fields: id, name, age
| id | name | age |
+----+------+-----+
| 1 | Fred | 56 |
| 2 | Adam | 27 |
Here is what happens; if I write:
Company.find_by_sql("SELECT * FROM `employees`")
I get:
Company Load (0.3ms) SELECT * from `employees`
=> [#<Company id: 1, name: "Fred">, #<Company id: 2, name: "Adam">]
I only get the fields of employees whose names match the ones in companies (i.e., the field age is missing)!
No #attributes at all.
Is it a bug? Can anyone please help me?
The console uses pretty printing to output data from any instances returned by the query. Pretty printing is implemented automatically in the class by ActiveRecord according to the columns associated with that particular model, and won't therefore display attributes that do not belong to that particular model.
That does not mean however the attributes were not loaded into the instances. Pretty printing is just not showing them, but they are still there.
So if you just do:
Company.find_by_sql("SELECT * from employees").first.age
You should still get 56 according to your example.
try:
Employee.find_by_sql("SELECT * FROM `employees`")
If you're selecting from the employees table you will want to use the Employee model.
Try this instead
Employee.find_by_sql("SELECT id, name, age FROM `employees`")

Resources