Rails: Finding models with missing has_one records - ruby-on-rails

If model User has_one Profile, is there a simple way to find all users who have no profile without a custom query (eg NOT User.where('profile_id IS NULL')) or processing it in the app?
Since the association between User and Profile is already known to Rails I don't want to restate it. I want to keep this DRY. The actual connection between the models is more complex than this simple example (uses keys and class name) and may change in the future.

As #tadman & #antonk already said, you probably want to use scope:
scope :without_profile, where(profile_id: nil)
EDIT:
To answer #David Mauricio's question: you could use it by calling User.without_profile, to return the AR association of all users with a nil :profile_id.
#DriverDan : then I'm really unsure what you're asking for. Ask another question with more details, and we can try to answer it!

Related

How do I associate two entries in a database that are connected through a many-to-many relationship in Rails?

How do I associate two entries in a database that are connected through a many-to-many relationship in Rails?
I'm trying to associate Users and Issues for an issue tracker. I'm using has_and_belongs_to_many, not :through. I have a :user_id and :issue_id available to me, but there doesn't seem to be User.issues.find(id) or Issue.users.find(id) available to me. I have a route post "/", to: "home#create". I'm trying to make a create method in home_controller.rb.
From the look of it you're calling the method on the User class and not an instance.
If you want to get the issues connected to a user you need to fetch the user first:
User.find(id).issues
If you want to add a record to the association you can use the shovel method or any of the methods generated by the association macro:
User.find(id).issues << Issue.find(3)
User.find(id).issues.push(Issue.find(3))
User.find(id).issue_ids = [1, 2, 3]
Besides that you have a smattering of naming issues in your schema. Use snake_case everywhere in your database schema unless you have a good reason why you want to break the conventions and feel like explicitly configuring table and foreign key names.
I would also really question if you really want to use has_and_belongs_to_many. It should only really be used if you can't foresee that you ever will need to add additional attributes to the join table or never need to query the table directly - it seems pretty unrealistic that that would be true in an issue tracker. You want has_many through: - pretty much always.
I have a route post "/", to: "home#create". I'm trying to make a
create method in home_controller.rb.
Don't throw everything into a junk drawer controller. Think about your app in terms of resources that can be CRUD:ed and create controllers that handle just that resource. You should think about what the relation between a user and an issue is in your domain and how you can model it as an actual entity in the domain logic instead of just plumbing.
Maybe all I need to do is direct you to Rails Guides: Active Record Associations.
There is neither of these
User.issues.find(id)
Issue.users.find(id)
because when you are finding an issue or user by id, you don't use the association. Instead use these:
Issues.find(id)
Users.find(id)
Since the :id is unique this will work and should be what you want.
The only time you want to query issues or users using the association will be when you have the data for the other end of the relationship.
user = User.find(user_id)
issue = user.issues.where(id: issue_id)
Since the :id field is unique, this is the same as Issues.find(id). However if you want to get a collection of a user's issues with some other data, you can put the condition for that data in the where.
You can create an issue for a user this way:
user = User.find(user_id)
issue = User.issues.create( ... )

Allowing admin and users to sign in using same form (rails)

I've created 2 tables, one for users and one for admins.
I created 2 tables as they both collect different information, but I want to be able to allow a sign in using an email address and password from both the admin and user tables via the same form.
Is this possible? I've looked around and people seem to have created 1 users table and added an admin boolean, but I wanted to avoid this and I didn't want to collect unnecessary data if I didn't need to.
Any help and assistance about how to best go around this would be great.
If you are implementing something from scratch, then it is simply a matter of coding it. I think this approach has some inherent flaws and I would avoid it.
If you want to have some segregation on the model side of things, I suggest you use STI. That way there is some shared behaviour/attributes and the distinctions can be coded separately, so you have your protection.
If you have plenty of distinct attributes, I would suggest separating them from your user/admin and creating an "admin_profile" model that belongs_to :admin and a "user_profile" that belongs_to :user.
And to make coding "transparent", you can create accessors in your admin model class to get/set the profile attributes seamlessly. Say you have an is_cool attribute on the admin_profile model, but you'd like to access it as
imadmin.is_cool
You can have in your admin.rb model
has_one :admin_profile
def is_cool
self.admin_profile.is_cool
end
be careful cause the has_one relationship may return nil if there is no profile associated with the admin/user.

Design question: Aliases for a Location model (Rails)

This is more of a general design question, but it will be implemented in RoR to which I am very much a newcomer. Also, I think this is my first question so please be gentle :)
The scenario is:
I have an Asset model. Each asset is located in a particular room, so I would also like a one-to-many relationship with a Location model. Simple enough. However, some rooms (Locations) also go by an alias (eg. 123 is aka Library). When a user wants to update information about a particular Asset, I would like them to be able to just search without worrying about whether they know the exact room number, and be shown a list of assets in that room.
To clarify, there could be more than one alias.
So the question is:
Would you recommend an Alias model for which a Location would have a one-to-many relationship? Or, would a self-referential (sort-of hierarchical) association be better? Or something else maybe? From what I can envisage, the former would require querying columns on different tables for the same sort of information, and the latter just doesn't seem right (an Alias is not the same as a Location).
This might be a good area for using the tagging plugin acts-as-taggable-on:
https://github.com/mbleigh/acts-as-taggable-on
In your model you can do:
class Location < ActiveRecord::Base
acts_as_taggable_on :aliases
end
Then in your controller do:
Location.tagged_with("library", :on => :aliases)

How does rails manage associations?

I'm still learning Ruby, and get caught up in alot of the 'magic', wanting to better understand what is actually happening, and making sure that I understand what it is doing.
I've got a user, and each user has entries.
In my user class, I have
has_many :entries
and in my entries class I have
belongs_to :user
I was expecting that the entries table would have a column for users, but I'm not seeing that when I 'describe' the database.
How do I know, or how does Rails know which user the entry is connected to? Or do I need to create a field myself to do that?
It seems strange to me that we have all these 'belongs_to', etc. yet it isn't explicit how that connection is made.
This is a common misconception. Associations do not create the database tables for you. Instead, you have to create them yourself. What you need to be careful of, is that an Entry model would have a user_id field, in order for the association to fully work. I truly would not want to advertise or anything, but i have created a blog post that can help you quite a lot i think :
http://www.codercaste.com/2011/02/06/rails-association-in-plain-english-what-i-wish-i-had-known-before-i-started/

Rails - Beginner wants feedback on how they've modeled their app and how to do it better

I think the way I've modelled my app is a bit fishy and i need to rejig things, im just not sure how. I've already re-jigged and refactored before. It took a long time ( I'm a beginner ) and I'm hesitant to it again in case i head off in the wrong direction again.
Basic Idea, user can submit an answer, another user can mark it correct or incorrect. If incorrect they have to write the correct answer. Users can view their and everybody else's correct and incorrect answers.
So I did it this way
class Answer
has_one: correction
end
class Correction
belongs_to :answer
end
when a user marks an answer as correct, I set checked_at:DateTime and checked_by_id:integer on the Answer object to keep track of who checked the answer and when.
For incorrect answers I create a correction object which holds the correct answer and again checked_by and checked_at details.
I don't like this because I have checked_by and checked_at in both models. It just doesn't sit right.
Possible solutions are:
Create a third model such as VerifiedAnswer and move the checked_by/at attributes to that. It will handle the situtation where an answer is marked correct.
Or are these models thin enough (they dont have any other attributes) that I can just have one model ( Answer ) that has all the attributes to store all this information?
I would make an answer corrected by another answer.
That way, you can keep correcting the new answer.
This could be done by specifying:
class Answer
belongs_to :correction, :class_name => "Answer"
end
Note that this will mean that any existing answers with corrections will have data set up incorrectly (since the correction_id is currently pointing to a separate table).
You would need to clear out your database for this to work.

Resources