Find by id or by object - ruby-on-rails

It's usal to see codes where a model where search in a foreign key is realized passing the whole object. For instance, search user exercises:
Exercise.where(user: user)
Another usual way to do that is:
Exercise.where(user_id: user.id)
Checking in console log, both querys search by the user id, but there is a "most recommended" way between both? If yes, why: more elegant, performatic?

I would choose the first one
Exercise.where(user: user)
It is mainly stylistic preference but also if the users every become polymorphic on exercises this would work without any changes whereas the second option would need to be changed to the first.
The benchmarks i quickly did showed no real performance difference.

Exercise.where('user_id = ?', user.id)
Not sure I understood your question correctly, but if you are looking for other ways to query or rather best practices then above is the right way to query in Rails.
The reason it is accepted as best practices is because its a Rails Security Countermeasure
Rails Guides: Array Conditions
Rails Security Guides: SQL Injections: Countermeasures
So to answer your question, yes there is good reasoning behind querying this way.

Related

Get the mobile number of the user in MongoDB [duplicate]

For performance reason, I use as often as possible the only() keyword when writing up a mongoid query in order to specify the fields I want to load.
The usual suspect, is for instance when I want a user's email of all my admins only for display purposes.
I would write:
User.where(:groups => :admins).only(:email).each do |u|
puts u.email
end
I do this because my user model are quite full of a lot of data that I can gladly ignore when listing a bunch of emails.
However, now let imagine, that my users are referenced via a Project model, so that for each project I can do: project.user. Thanks to mongoid's lazy loading, my object user will only get instantiated (and queried from the DB) when I call upon the reference.
But what if I want to list all the email of the owner of all admin project for instance ?
I would write this:
Project.where(:admin_type => true).each do |p|
puts p.user.email
end
The major problem here is that doing this, I load the entire user object for each projects, and if there are lots of project matching the query that could get pretty heavy. So how do I load only the emails ?
I could do this:
User.where(:_id => p.user_id).only(:email).first.email
But this obviously defeat the purpose of the nice syntax of simply doing:
p.user.email
I wish I could write something like: p.user.only(:email).email, but I can't. Any ideas ?
Alex
Answer from creator of Mongoid. It's not possible yet. It's been added as feature request.
I think you need to denormalize here. First of all, read A Note on Denormalization.
You can implement denormalization by self using mongoid events or use great mongoid_denormalize gem. It pretty straight and after implementing it you could use p.user_email or something in your queries.

Which approach should I use to store translation of products in database?

I'm creating an application where products will be created by my customer (something like an e-commerce website), so I obviously require translated descriptions stored in database, I can't force my customer to learn git/yml.
I have two ideas on how to correctly localize descriptions (and eventually product name) and store them in database, but if there is a well-known approach that I should use, I would be really happy to know it.
The first idea seems the most logical for me, but I would like to make it "transparent" to me, I don't want to write joins everywhere, so some suggestion on how to achieve this, if it's the correct one, would be appreciated.
Idea 1:
Create a database table products (with name and description field set maybe to the default locale language), then a products_translations table which contains a table structured in this way:
products_translations
- id
- locale
- product_id
- name
- description
As an example: product_translation: { id: 1, locale: 'en', product_id: 3, name: 'toy', description: 'play' }
But I want to access to translations without the requirement to write a lot of IFs everywhere. So if I write product.name it should return en or it based on current locale.
Bonus: Are there any gems that can help me to achieve this?
Idea 2: The other idea is to have a table with name_locale1, name_it and so on, but I don't like this approach because will pollute my model objects with fields and I will have a giant table.
However, in this way I can avoid join on every query for that object.
If there is a greater approach which I don't know about (a database pattern or similar), it's ok that too, I'm not forced to strict to only these two ideas, however I have to choose between the two and I really don't know which could be better.
Important: I would like to keep translations stored in yml files, except for dynamic contents, which obviously require translations in database.
I agree with PinnyM that the first approach is the better of the two, but rather than implement your own schema, I would highly recommend you implement Globalize3 where most of the structural decisions have been taken for you (and by Mr Fuchs himself, no less). Also, with the rails helpers, you just call something like product.name on a model instance and the gem will figure out how to display it in the correct locale, awesome!
The first approach is the recommended one. As you surmised, the second approach is not as clean and requires more work on the coding end with no real gain since you still have to join on this monster table. To the contrary, the first method requires at most one join, while the second approach requires a join on each attribute you may want to add localization support.
You can simply append a scope on all your product calls such as:
scope :for_locale, lambda{|locale| joins(:product_translations).
where(product_translations: {locale: locale || 'en'}) }
and pass in the session locale (or wherever you are storing it).

Thinking sphinx with privacy settings using facets?

I'm trying to use Thinking Sphinx with my Can Can solution for authorization.
I found this answer helpful Cancan Thinking Sphinx current_ability Questions, but was wondering if there might be a way to accomplish this with facets.
So I have projects, where there is a column called privacy which is a bool. If a project is private then there is an index for collaborator_ids, which is a list of all of the users that can view the project.
I was wondering if there is a way to form a query using facets to return all projects that are either public OR private and the user's id is in the collaborator_ids.
Another approach I'm considering is formulating an extended query in my controller to check for these fields. http://sphinxsearch.com/docs/current.html#extended-syntax
I have no idea how you would do it thinking sphinx, but in normal sphinx this should work..
$cl->setSelect("*,privacy+IF(IN($user_id,collaborator_ids),1,0) AS myint");
$cl->setFilter('myint',array(1,2));
Which effectily makes an 'OR' query.
As I say, cant help you write thatin in thinging-sphinx.

How to change primary ID of a record in Rails?

rails console
u = User.find(9)
u.id = 7 # There is no other record with id 7
u.save
=> true
User.all
The id has not changed.
How to change the primary ID? Why does it prevent this action?
Working in Rails 3.0.7 and PostgreSQL.
EDIT:
Since there are good reasons not to do this, I'll explain why and hopefully it is a good reason.
We are doing Usability Testing on Staging, so I want it to look like the Production to make it easy for everyone. I don't want to create confusion or errors in the Usability Testing process by having some things in one order on Staging and in a different order on Production. I only changed one PK id on Staging DB.
Don't do this on your production DB!
I'm not sure as to why it prevents that action, but it does for sure prevent it.
You can bypass this using the update_all method on for the user.
User.where(id: 7).update_all(id: 9)
Though if possible, you really should avoid doing this.
For me worked:
User.find(9).update_column(:id, 7)
Could you elaborate what your use case is? Why do you want to change the ID? What are you really trying to accomplish with it?
Generally it's a bad idea to do this, and Rails won't let you do this easily because it will break your data integrity!
Here's Why:
When you're using a relational database (like PostgreSQL) underneath, you will have relationships between your models, which means that you will use the model's IDs as a reference in other related models... which means that if you change an entry's ID , all those references to that entry will go stale and corrupt your database..
I would strongly suggest to analyze your requirements again, and try to find another way to accomplish what you need to do (without changing IDs)
#Jason pointed out a very valid point. I totally agree with him. But, you might have your reasons and I suggest you re-consider what you're trying to do.
To answer your question:
ID columns are protected by default for mass assignment and cannot be set manually. But, you can override this behavior by defining a method:
def self.attributes_protected_by_default
[] # ["id", ..other]
end
This will allow you to assign id's manually.
Another method (although it is not pure Rails) is to create a new column, and populate it with your new IDs.
Then, using DB management software (not Rails), remove the Primary Key attribute from the id column, delete it, rename your recently added column to "id", and give it the Primary Key attributes. (If you cannot do that directly in your DB software, then set the properties Unique, Auto-Increment, etc.)
You can also move the column to the front (MySQL syntax):
ALTER TABLE table_name MODIFY COLUMN id int(11) FIRST;
But there is another thing I'd really like to say. It hasn't been as bad on this question as I've seen elsewhere, but folks: it's all well and good to tell people it's USUALLY not a good idea, but that isn't an answer to the question. Please refrain from saying "Don't do that" unless you already know the person's use-case.
In other forums I've been greatly frustrated by people saying "Why do you want to do that?" or "Don't do that", and then not answering the question. They didn't give me credit for already KNOWING that it isn't standard practice, and they ASSUMED I didn't already know that it was not an ordinary use-case.
People on this page haven't been that bad, and I'm not trying to pick on them. I'm just admonishing: please, check your own behavior before presuming to lecture. Somebody asked a question, and while warnings may be a good idea, it is probably safe to presume they have a REASON for wanting an answer.
End of rant.
The ID is typically generated by the database as an auto-incrementing PK. You can't (and really shouldn't need) to modify it.

Performance differences between '.find' and '.where' methods

I am using Ruby on Rails 3.0.7 and I would like to know, regarding performance matters, what are differences between the User.find(<id>) method and the User.where(:id => <id>) method.
Under the hood, find does more or less what you're describing with your where. You can find the details in this post. That being said, if you're looking to grab a single record by id, then you might want to use find_one. That's what find winds up doing when you call it with a single argument of an id, but you'll skip past all the other code it needs to run to figure out that's what you wanted.
Short answer, but: It really doesn't matter (unless you don't have a unique-constraint on your id column).

Resources