Order by A then B using Ruby on Rails Model - ruby-on-rails

This is not a homework question. I am trying to learn more.
I have the following entities with attributes
Manufacturer {name} //Store Manufactueres
Model {manufacturer_id, name} //Store Models
Tint {manufacturer_id, model_id, front, side, rear} //Store measurements
I have the follow data in my Tint entity. Alphabets stands for different manufacturer name and models.
Manufacturer | Model | Front | Side | Rear |
-------------+-------+-------+------+-------
A | AD | 10 | 10 | 10 |
B | AB | 10 | 10 | 10 |
A | AA | 10 | 10 | 10 |
A | AC | 10 | 10 | 10 |
B | AA | 10 | 10 | 10 |
A | AB | 10 | 10 | 10 |
When I print it out in view, I would like to have it sorted based on Manufacturer name and then Model. So the result will be as below. The name of the Manufactures will be sorted alphabetically, then Models.
Manufacturer | Model | Front | Side | Rear |
-------------+-------+-------+------+-------
A | AA | 10 | 10 | 10 |
A | AB | 10 | 10 | 10 |
A | AC | 10 | 10 | 10 |
A | AD | 10 | 10 | 10 |
B | AA | 10 | 10 | 10 |
B | AB | 10 | 10 | 10 |
I have setup the model to make sure Manufacturer and Model is a distinct pair of values.
My question is since I am referencing using manufacturer_id and model_id, how can I get the name of the Manufacturer and Model from Manufacturer and Model table.
In my tints_controller.rb, I have #tints = Tint.all.order(:manufacturer_id). However, it will only sort based on the manufacturer_id (as in numbers) instead of the name of the manufacturer.
I know that I can do it in SQL way (SELECT, FROM, WHERE) in RoR model. However, I would like to know is it possible to use ActiveRecord to sort the data based on their name.

If I understand correctly, you have 3 models, Tint, Manufacturer and Model. I am assuming you have the appropiate has_many and belongs_to associations setup correctly.
Tint.rb
belongs_to :workspace
Manufacturer.rb
has_many :models
has_many :tints, through: :models
Model.rb:
belongs_to Manufacturer
has_many :tints
You need to first join the three models together, and then order by some criteria
tints_controller.rb
#tints = Tint.joins(model: :manufacturer).order('manufacturers.name, models.name').pluck('manufacturers.name, models.name, tints.front, tints.side, tints.rear')
That will give you all tints records and they appropiate models and manufacturers.

Any time you have the id of an entity in Rails, you can easily retrieve other associated fields simply by instantiating that entity:
#manufacturer = Manufacturer.find(params[manufacturer_id])
Then it's a simple matter to retrieve any of the other fields:
#manufacturer_name = #manufacturer.name
If you need a collection of manufacturers or manufacturer names, then it's advisable to build yourself an ActiveRecord::Relation object immediately via a scoped query (as you already know). I have no idea what your criteria are, otherwise, I'd supply some sample code. I can tell you that your scoped query should include an .order clause at the end:
#manufacturers = Manufacturer.where("some_column = ?", some_criterion).order(:sort_field)
In the above example, :sort_field would be the field by you want to sort your ActiveRecord::Relation. I'm guessing in your case, it's :name.
All this having been said, if you want fancy sorted tables, you should look into the JQuery DataTables gem. DataTables can do a lot of the heavy lifting for you, and it's convenient for your users because they can then sort and resort by any column you present.

In your tints_controller.rb, instedad of
#tints = Tint.all.order(:manufacturer_id)
please write:
#tints = Tint.all.order(:manufacturer_id, :model_id)

Answer to my question:
In tints_controller.rb, I wrote
#tints = Tint.joins(:manufacturer, :model).order("manufacturers.name ASC, models.name ASC") to join the table and order them accordingly.
I tried the answer provided by #Goston above and I had an issue when I was trying edit the tints. It did not allow me to edit.
Note: Answer provided by #Goston will order them, but it broke the edit function for my case.

Related

Graph Modelling a 'transitive' relationship

This is a followup to an earlier question that I had posted and accepted an answer. I have a further question after getting feedback, and trying to post as a new question to hopefully get an answer.
Having discussed with users, the requirement just got more complex. What they actually do is something like a table in relational world with following columns (its denormalised with lot of repetitive data:
PartnerName | Service | Offered? |CurrentlyUsing | WeCouldSellThese |
XX | Baking | Yes |Competitor A, B | Product A |
XX | Baking | Yes |Competitor A, B | Product C |
XX | Baking | Yes |Competitor A, B | Product D |
XX | OnlyDough| Yes |Product A | Product C |
XX | Packing | No | | Product E |
Basically, they need to store information what is being used currently, and whether its currently offered by partner or not, they still try to sell them products (Offered Yes or No will both still lead to a market). There is a many-to-many relationship between service and product as well...which means there is a "3node" relationship - A particular partner for a particular product for a particular service, here are the 2 options I'm thinking of. The trouble with Option 1 is that Product A would have many To_Build outgoing relationships, so I dont have a way to figure out its for which partner.
Here are the options after I bring a new entity to split the relationship:
You can use an extra node (say, labelled "Build") to "reify" the "3-node relationship". For example:
By the way, you should also consider whether the Could_Offer relationship is redundant. For example, you could add an isOffered property to the Could_Build relationship and eliminate the Could_Offer relationship.

Odata breaking with unconventional association

I'm trying to make an unconventional join, like this:
builder.HasOne(x => x.MATERIAL_OBJ)
.WithMany()
.HasForeignKey(c => c.MATERIAL)
.HasPrincipalKey(p => p.MATERIAL_CODE);
because the data from one of my tables comes from an external source, and I need to make a join with another table by a non-PK (VARCHAR) field.
My tables are as follow:
Transits table
+---------+----------+
| ID | MATERIAL |
+---------+----------+
| 1 | ABC |
| 2 | HIJ |
+---------+----------+
Material table:
+---------------+---------------+
| MATERIAL_CODE | SUPPLIER_NAME |
+---------------+---------------+
| ABC | SUP 1 |
| DEF | SUP 2 |
+---------------+---------------+
The transits table always comes filled, and sometimes with materials we dont have avaliable. If we have the material, then the object comes filled correctly, the problem I'm facing is that whenever the material doesn't exist in the table, my odata simply doesn't work properly, breaking the return object, like so:
Is there any way to odata to return null, instead of breaking the return?
EDIT: below is the return value:
{"#odata.context":"http://MYAPI/odata/$metadata#TRANSIT(Id,MATERIAL,MATERIAL_OBJ,MATERIAL_OBJ()","value":[{"Id":12567,"MATERIAL":"REDACTED"
Also, this seems to be something with odata, as the objects are filled in the API.
I figured out that was a problem with EF Core because of the unconventional mapping I did. I decided to do a View instead and mapped that to EF.

Ruby on Rails: Join Tables Concept

So I have been out of the coding game for a while and recently decided to pick up rails. I have a question about the concept of Join tables in rails. Specifically:
1) why are these join tables needed in the database?
2) Why can't I just JOIN two tables on the fly like we do in SQL?
A join table allows a clean linking of association between two independent tables. Join tables reduce data duplication while making it easy to find relationships in your data later on.
E.g. if you compare a table called users:
| id | name |
-----------------
| 1 | Sara |
| 2 | John |
| 3 | Anthony |
with a table called languages:
| id| title |
----------------
| 1 | English |
| 2 | French |
| 3 | German |
| 4 | Spanish |
You can see that both truly exist as separate concepts from one another. Neither is subordinate to the other the way a single user may have many orders, (where each order row might store a unique foreign_key representing the user_id of the user that made it).
When a language can have many users, and a user can have many languages -- we need a way to join them.
We can do that by creating a join table, such as user_languages, to store every link between a user and the language(s) that they may speak. With each row containing every matchup between the pairs:
| id | user_id | language_id |
------------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 4 |
| 4 | 2 | 1 |
| 5 | 3 | 1 |
With this data we can see that Sara (user_id: 1) is trilingual, while John(user_id: 2) and Anthony(user_id: 3) only speak English.
By creating a join table in-between both tables to store the linkage, we preserve our ability to make powerful queries in relation to data on other tables. For example, with a join table separating users and languages it would now be easy to find every User that speaks English or Spanish or both.
But where join tables get even more powerful is when you add new tables. If in the future we wanted to link languages to a new table called schools, we could simply create a new join table called school_languages. Even better, we can add this join table without needing to make any changes to the languages SQL table itself.
As Rails models, the data relationship between these tables would look like this:
User --> user_languages <-- Language --> school_languages <-- School
By default every school and user would be linked to Language using the same language_id(s)
This is powerful. Because with two join tables (user_languages & school_languages) now referencing the same unique language_id, it will now be easy to write queries about how either relates. For example we could find all schools who speak the language(s) of a user, or find all users who speak the language(s) of a school. As our tables expand, we can ride the joins to find relations about pretty much anything in our data.
tl;dr: Join tables preserve relations between separate concepts, making it easy to make powerful relational queries as you add new tables.

Retrieving data in Rails both ways from 2 column join table

I have a ChunkRelationship model with a table that looks like this:
+----+---------------+----------------+---------------------+---------------------+
| id | chunk_id | chunk_partner | created_at | updated_at |
+----+---------------+----------------+---------------------+---------------------+
| 1 | 1 | 2 | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 |
| 2 | 2 | 1 | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 |
+----+---------------+----------------+---------------------+---------------------+
Both entries are foreign keys to a Chunk model. Right now, the relationship is being saved twice, once in both directions ( 2 => 1 and 1 => 2). But the relationship can be saved once, because if one ID is known then the other can be found (What is this type of table called?).
I am wondering what the Rails way of doing that would be. I was thinking of creating a before_validation callback on the ChunkRelationship model and taking the smallest number of the two and always saving that to the chunk_id column, which would allow for checking for duplicates easier before saving. But from there I'm not sure how I would retrieve them.
The intended end result would be for chunk.partners to return all the rows paired with it, no matter which column either one is in.
Perhaps you are looking for the has_many_and_belongs_to association: http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
This should create a many-to-many relationship which I believe you are describing.

select distinct records based on one field while keeping other fields intact

I've got a table like this:
table: searches
+------------------------------+
| id | address | date |
+------------------------------+
| 1 | 123 foo st | 03/01/13 |
| 2 | 123 foo st | 03/02/13 |
| 3 | 456 foo st | 03/02/13 |
| 4 | 567 foo st | 03/01/13 |
| 5 | 456 foo st | 03/01/13 |
| 6 | 567 foo st | 03/01/13 |
+------------------------------+
And want a result set like this:
+------------------------------+
| id | address | date |
+------------------------------+
| 2 | 123 foo st | 03/02/13 |
| 3 | 456 foo st | 03/02/13 |
| 4 | 567 foo st | 03/01/13 |
+------------------------------+
But ActiveRecord seems unable to achieve this result. Here's what I'm trying:
Model has a 'most_recent' scope: scope :most_recent, order('date_searched DESC')
Model.most_recent.uniq returns the full set (SELECT DISTINCT "searches".* FROM "searches" ORDER BY date DESC) -- obviously the query is not going to do what I want, but neither is selecting only one column. I need all columns, but only rows where the address is unique in the result set.
I could do something like Model.select('distinct(address), date, id'), but that feels...wrong.
You could do a
select max(id), address, max(date) as latest
from searches
group by address
order by latest desc
According to sqlfiddle that does exactly what I think you want.
It's not quite the same as your requirement output, which doesn't seem to care about which ID is returned. Still, the query needs to specify something, which is here done by the "max" aggregate function.
I don't think you'll have any luck with ActiveRecord's autogenerated query methods for this case. So just add your own query method using that SQL to your model class. It's completely standard SQL that'll also run on basically any other RDBMS.
Edit: One big weakness of the query is that it doesn't necessarily return actual records. If the highest ID for a given address doesn't corellate with the highest date for that address, the resulting "record" will be different from the one actually stored in the DB. Depending on the use case that might matter or not. For Mysql simply changing max(id) to id would fix that problem, but IIRC Oracle has a problem with that.
To show unique addresses:
Searches.group(:address)
Then you can select columns if you want:
Searches.group(:address).select('id,date')

Resources