Ruby on Rails: Proper Syntax for 2 dimensional Array in Database - ruby-on-rails

I plan to insert a two-dimensional array into the database with ActiveRecord.
The reason why: I want users to select multiple languages and the corresponding language-levels (like how good they speak it). I do not want to have two fields for both languages & language_levels, I want those two to be hooked together from the beginning. Sure, I could hook them together later on the model level, but I want to try it the other way first.
Example:
[ ["English",2], ["German",1], ["Japanese",1] ]
I've been able to store one-dimensional arrays, though had no luck with these. Trying to make those accessible using something like (languages: [][]) in the strong parameters didn't work.
Thanks

I understand your intent to do this with sort of minimal effort, but you should definitely consider looking into storing things the normalized way.
The intention is – what to do with lang. skills for all your users, once there's a need to rename a language? Say you had Chinese language as of the start, but then you've decided to keep two of them, Chinese (traditional) and Chinese (simplified). You'd now have to write an error-prone update script.
In case of keeping the languages normalized way, I'd keep three models for consistency:
class User < ActiveRecord::Base
has_many :language_skills
has_many :languages, through: :language_skills
end
class Language < ActiveRecord::Base
has_many :language_skills
has_many :users, through: :language_skills
end
class LanguageSkill < ActiveRecord::Base
belongs_to :user
belongs_to :language
end

I would definitely go for something like
User
has_many languages_skills
LanguageSkill
belongs_to User
language: string
level: integer
Then use nested forms to add everything together
I would NOT use multi-dimensional arrays

Related

How to increase performance using association in rails

Hi can anyone tell me how can i increase performance if association returns large no. of records. for example in my app :-
class Restaurant < ActiveRecord::Base
has_many :inventory_items
end
class InventoryItem < ActiveRecord::Base
belongs_to :vendor
end
i am trying to find the vendors of my restuarant as follow :-
current_restaurant.inventory_items.includes(:vendor).uniq
current_restaurant.inventory_items returns large no. of records which takes maximum time. so how can i reduce this time please help me.
There are a number of solutions that you can use depending on how your application is configured and what it needs to do -
Only select the columns that you want, for example, if you are only looking for the IDs, you can use the pluck or select methods.
As Chetan suggested in his answer, you can also add scopes, and in addition to that also add indexes for the columns in the scope depending on what kind of columns they are.
If you are looking at calculated values, consider caching them on the Restaurant table.
You can add a scope to your model and add a condition for the records you wanna fetch. Like
scope :your_scope_name, -> { includes(:vendor).where(*some more conditions*) }
This will help query to not to go through all data
Use pagination, loading all records is never recommended..
see will_paginate OR kaminari gems
Update:
class Restaurant < ActiveRecord::Base
has_many :inventory_items
has_many :vendors, through: :inventory_items
end
Then,
current_restaurant.vendors.uniq
It depends on the size of the tables and how they are indexed, one sub query might be faster than a huge join:
Vendor.where(id: current_restaurant.inventory_items.select(:vendor_id).distinct)

Should I use a LIKE query for these ActiveRecord relationships?

Let's say I have a single web page form user interface with 2 sets of checkboxes. With set 1 checkboxes, I can check off what Trainers I would like ("Jason", "Alexandra, etc.) With set 2 checkboxes, I can check off what animals I would like to see ("Tigers", "Bears", etc.) Once I submit the form with these options, I get back a list of zoos that match the criteria (let's assume all the trainers work at all the zoos and all the animals are at all the zoos for discussion's sake)
We'll be running our database query by "name" (e.g., search using trainer names and animal names, NOT database ids)
Let's say we are using a Postgres database that has hundreds of thousands of rows (if not millions).
Is it more efficient to search using an "ILIKE" query or is it better to do a standard join query (e.g., Zoo.includes(:animals, :trainers).where("animals.name = ? and trainers.name = ?", animal_names, trainer_names)?
Is there a better way than what I just showed in #1 above?
model setup
class Zoo < ActiveRecord::Base
has_many :animals, through: zoo_animals
has_many :trainers, through: zoo_trainers
has_many :zoo_trainers
has_many :zoo_animals
end
class Animal < ActiveRecord::Base
has_many :zoos, through :zoo_animals
has_many :zoo_animals
end
class Trainer < ActiveRecord::Base
has_many :zoos, through :zoo_trainers
has_many :zoo_trainers
end
class ZooAnimal < ActiveRecord::Base
belongs_to :animal
belongs_to :zoo
end
class ZooTrainer < ActiveRecord::Base
belongs_to :zoo
belongs_to :trainer
end
EDIT: let's suppose I don't have access to the database ID's.
LIKE '%Jason%' is much less efficient than querying for the exact string 'Jason' (or querying for an ID), because while exact comparisons and some uses of LIKE can use an index on the column being queried, LIKE with a pattern beginning with a wildcard can't use an index.
However, performance doesn't sound like the most important consideration here. LIKE %Jason% will still probably be fast enough on a reasonably sized database under reasonable load. If the application really needs to search for things by substring (which implies that a search might have multiple results), that requirement can't be met by simple equality.
There are an endless number of higher-powered solutions to searching text, including Postgres built-in full-text search and external solutions like Elasticsearch. Without specific requirements for scaling I'd go with LIKE until it started to slow down and only then invest in something more complicated.

In Rails, what do keywords belongs_to, has_many, etc, actually do?

I understand the concept of relational databases, primary/foreign keys, etc, however, I'm having trouble seeing the actual result of setting these properties up in my models. Do they generate helper functions or something similar? or do they simply work on a database level?
For example, if I have these two models (other properties omitted)
class Course < ActiveRecord::Base
has_and_belongs_to_many :schedules
has_many :sections
end
class Section < ActiveRecord::Base
belongs_to :course
end
I could simply get all sections for any given course like this:
Section.where(course_id: 1234)
However, I could do this without having set up the relations at all.
So my question is: Why do we do this?
Adding these methods let's you do things like this:
Section.find(5).course # <== returns a 'Course' model instance
Also it let's you join your queries more easily:
Section.joins(:course).where(course: {name: "English"}) # <== returns sections who have the 'english' course
Neither of these would be possible if you didn't set up the relations in the model.
Similarly:
Course.find(8).sections # returns an array of sections with 'course_id = 8'
It makes your calls more semantic, and makes things easier from a programmatic perspective :)
Relations are applied on instances of an object. So, these relations allow you to get related objects to an instance of another.
For example, say you have an instance of Section (called #section). You'd be able to get all Course objects for that section by doing:
#section.course if you have belongs_to :course set up.
Similarly, if you have an instance of Course, you can get all Section objects for that Course with:
#course.sections if you have has_many :sections.
TL;DR - these are helper scopes for instance variables of Course and Section.

How many classes is too many? Rails STI

I am working on a very large Rails application. We initially did not use much inheritance, but we have had some eye opening experiences from a consultant and are looking to refactor some of our models.
We have the following pattern a lot in our application:
class Project < ActiveRecord::Base
has_many :graph_settings
end
class GraphType < ActiveRecord::Base
has_many :graph_settings
#graph type specific settings (units, labels, etc) stored in DB and very infrequently updated.
end
class GraphSetting < ActiveRecord::Base
belongs_to :graph_type
belongs_to :project
# Project implementation of graph type specific settings (y_min, y_max) also stored in db.
end
This also results in a ton of conditionals in views, helpers and in the GraphSetting model itself. None of this is good.
A simple refactor where we get rid of GraphType in favor of using a structure more like this:
class Graph < ActiveRecord::Base
belongs_to :project
# Generic methods and settings
end
class SpecificGraph < Graph
# Default methods and settings hard coded
# Project implementation specific details stored in db.
end
Now this makes perfect sense to me, eases testing, removes conditionals, and makes later internationalization easier. However we only have 15 to 30 graphs.
We have a very similar model (to complicated to use as an example) with close to probably 100 different 'types', and could potentially double that. They would all have relationships and methods they inheritated, some would need to override more methods then others. It seems like the perfect use, but that many just seems like a lot.
Is 200 STI classes to many? Is there another pattern we should look at?
Thanks for any wisdom and I will answer any questions.
If the differences are just in the behavior of the class, then I assume it shouldn't be a problem, and this is a good candidate for STI. (Mind you, I've never tried this with so many subclasses.)
But, if your 200 STI classes each have some unique attributes, you would need a lot of extra database columns in the master table which would be NULL, 99.5% of the time. This could be very inefficient.
To create something like "multiple table inheritance", what I've done before with success was to use a little metaprogramming to associate other tables for the details unique to each class:
class SpecificGraph < Graph
include SpecificGraphDetail::MTI
end
class SpecificGraphDetail < ActiveRecord::Base
module MTI
def self.included(base)
base.class_eval do
has_one :specific_graph_detail, :foreign_key => 'graph_id', :dependent => :destroy
delegate :extra_column, :extra_column=, :to => :specific_graph_detail
end
end
end
end
The delegation means you can access the associated detail fields as if they were directly on the model instead of going through the specific_graph_detail association, and for all intents and purposes it "looks" like these are just extra columns.
You have to trade off the situations where you need to join these extra detail tables against just having the extra columns in the master table. That will decide whether to use STI or a solution using associated tables, such as my solution above.

How do I get a value from a composite key table using a Rails model?

I have the following schema (* means primary key):
languages
id*
english_name
native_name
native_to_target_language
native_language_id*
target_language_id*
target_language_name
overview_text
(target_language_name is the name of the target language as written in the native language).
I want to get the value of target_language_name from the native_to_target_language table given values for native_language_id and target_language_id.
What is the best way to go about getting this? Use Composite Primary Keys from http://compositekeys.rubyforge.org/? Is there a standard way WITHOUT using a raw SQL query?
Its not very clear if you need CRUD operations. If you want to find then you can do the following:
NativeToTargetLanguage.find(:all, :conditions => {
:native_language_id => native_language_id,
:target_language_id => target_language_id }
)
Instead of rolling your own translation system, have you investigated any "off the shelf" varieties?
For example there's Globalize which does a lot of this for you.
Having a table with a compound key that represents a connection from one record in a table to another is going to be so much trouble. Generally you need to maintain an A<->B association as a pair of A->B and B->A varieties.
What about this as a general example:
class Language < ActiveRecord::Base
belongs_to :phrase
has_many :translations,
:through => :phrase
end
class Phrase < ActiveRecord::Base
has_many :translations
end
class Translation < ActiveRecord::Base
belongs_to :language
belongs_to :phrase
end
In this case Phrase is a kind of record representing the term to be translated. It could represent "French" or "English" or "Click Here" depending on the circumstances.
Using this structure it is straightforward to find the proper term to describe a language in any language you have defined.
For example, roughly:
<%= link_to(Language.find_by_code('fr').phrase.translation.find_by_language_id(session_language_id), '/fr') %>
It sounds like you might want something like Polymorphic Associations. This would require a separate table per language, which is (I think) what you are discussing.
However, it seems like there might be a better solution to your problem. Particularly, you might be able to come up with a better schema to solve this (unless the database is already in use and you are creating a Rails app to try to access it).
Can you describe the overall problem you are attempting to solve?

Resources