For example, I have a model Hobby. And I have a User model, and user has many hobbies. Hobby also has many users. And I have a linking table UserHobby (belongs to user, belongs to hobby).
Some user registers on a site, picks some hobbies, and then saves this list. Technically creates an array of records. So on my backend part I have to do something like this:
UserHobby.create( user: user, hobby: params[:hobbies]), where :hobbies is an array. But it doesn't work this way.
Is there a way to do this without using something like params[:hobbies].map{ |hobby| UserHobby.create( user: user, hobby: hobby) } ?
The map is fine, but when creating associations use association methods.
params[:hobbies] is a param coming from a form, so presumably it contains an Array of Hobby IDs (perhaps better as params[:hobby_ids]). Since these Hobbies already exist in the database, we can simply append them to the user's list of hobbies. This will insert the necessary rows in the join table.
user.hobbies << Hobbies.where(id: params[:hobbies])
user.hobbies is cached and Rails will only check the database once. If you do UserHobby.create!(user: user, hobby: hobby) then user.hobbies will be out of date. If you update user.hobbies directly then user.hobbies will be updated.
Related
I'm on a project with Rails, Postgresql and Active Record, where I have Users, that can be either Influencers, or Creators.
The Users have common columns such as email, password, first_name and last_name, but :
influencers will have followers, eg_rate, account columns
creators will have SIRET_number and specialty columns
How can I design my database so Influencers and Creators are kind of "child" of the Users table ? I mean, is it possible to have a db where I can access a User' followers or a User's specialty with one query, or I'll always have to do multiple queries to achieve this ? I've tried to create three tables for each, with a foreign key user_id in Influencers table and Creators table. I also tried to add a user_type column to my User table where I pass the values of either "influencer" or "creator", but I'm kind of lost on how to link every tables...
Thank you everyone.
Your approach is right.
You can create a table users with the common columns and add a foreign key to influencers and creators tables.
Then when you need to retrieve the data, you can use ActiveRecord relations to easily fetch data and use ActiveRecord's includes method for relations.
For example:
class Creator < ActiveRecord::Base
# The relation must be set
has_one :user
end
# To fetch data anywhere else:
Creator.find_by(SIRET_number: 1234).includes(:user)
If you need to retrieve a creator or influencer by an attribute from related users table, you can use joins:
Creator.joins(:users).where(users: {email: "foo#bar.com"})
Make sure you have the relations set in both User and Creator models.
Check out this topic for more info.
By using includes or joins instead of using creator.user you'll avoiding the unnecessary additional query. The downside is the syntax is now longer, you can maybe create your own getters to easily retrieve data instead of writing "includes" everytime.
Also assuming you're not aware of this method, I suggest you to read about the common N+1 problem with Rails & ActiveRecord. The same methods can solve a lot of problems for you.
I am creating a few records programmatically based on a users input and creating an array of records to import.
When I check the database I can see the relationship has been created if they are new records.
If one of the records already exists in the database I can see an entry of the following in the association table but I can also see the new records have been created in their respective table so they exist but the records ID is not being updated in the association table.
user_id: 1
keyword_id: null
but if I run the code for a second time it will add the relationship correctly.
This is my code
records_to_add = []
words.each do |word|
keyword = Keyword.find_or_initialize_by(
word: word,
device: device,
)
records_to_add.push(keyword)
end
keywords_added = Keyword.import records_to_add, on_duplicate_key_ignore: true, validate: true
user.keywords << records_to_add
I think there is something wrong with this part of the code
user.keywords << records_to_add
It isn't creating the relationship correctly if one of the records already exists...
You are calling 'find_or_initialize_by' in your words loop, and then importing those records, which creates a new row in your Keyword table for all the new records.
So far, so good.
Then your script takes the first list (persisted and new records) and attempts to associate them to the user. At this point, it creates associations for existing Keyword records, but tries to create new Keyword records again for the ones that it just created in the import and associate those. These probably fail a unique validation at that point, and are not associated nor persisted.
That leaves you with just the unassociated but newly created records.
I have a relationships model that holds 2 user_ids, a follower_id and a followed_id
When a user "follows" another user a relationship record is added which includes these two id's. I would like the followed user to have some say as to what the following user can see, so I am thinking of adding adding field(s) to the record, such as "followed_user_allows_follower_to_see_email_address" (it would be a less verbose)
This seems like the correct place to add these attributes, are there any reasons I should store these some place else?
Is there any reason I should not just store a list of permissions, rather than an attribute for each permission? For example followed_user_allows_follower_to "see_email_address,see_some_other_detail,yet_another_detail" vs a separate field for each permission.
I watched this rails cast http://railscasts.com/episodes/22-eager-loading but still I have some confusions about what is the best way of writing an efficient GET REST service for a scenario like this:
Let's say we have an Organization table and there are like twenty other tables that there is a belongs_to and has_many relations between them. (so all those tables have a organization_id field).
Now I want to write a GET and INDEX request in form of a Rails REST service that based on the organization id being passed to the request in URL, it can go and read those tables and fill the JSON BUT NOT for ALL of those table, only for a few of them, for example let's say for a Patients, Orders and Visits table, not all of those twenty tables.
So still I have trouble with getting my head around how to write such a
.find( :all )
sort of query ?
Can someone show some example so I can understand how to do this sort of queries?
You can include all of those tables in one SQL query:
#organization = Organization.includes(:patients, :orders, :visits).find(1)
Now when you do something like:
#organization.patients
It will load the patients in-memory, since it already fetched them in the original query. Without includes, #organization.patients would trigger another database query. This is why it's called "eager loading", because you are loading the patients of the organization before you actually reference them (eagerly), because you know you will need that data later.
You can use includes anytime, whether using all or not. Personally I find it to be more explicit and clear when I chain the includes method onto the model, instead of including it as some sort of hash option (as in the Railscast episode).
I have a custom membership provider which I extended - added a couple of fields, first name, last name, adress, zip code and city.
now, these fields reside in the aspnet_Membership table so that I can easily access them when using the static Membership asp.net class.
now, I want to be able so save customer purchase order data (first name, last name, adress, zip code and city) to the database.
should I in my order model/table use a new set of fields - first name, last name, adress, zip code, city or should I create a relationship between my asp_Membershihp table and my Orders table?
Also, If i have dupe data, once a users asks for his account to be removed I wont have any orphan rows in my Orders table if I use the first method.
so, which is best, to have the user data, first name, last name, adress, zipcode, city in only one table and create a relationship between aspnet_Membership table and Orders table OR create the dupe fields in my Orders table with no relationship to the aspnet_Membership table? Pros cons?
Thanks!
/P
In this scenario, i would rather have the relationship.
Also being the data you are storing Orders (i assume at least, from the name :)) i would maintain a separate set of data on the Order, so one would optionally be able to specify different billing/shipping data than it's Identity on the site.
Another valid reason for duplicate at least some data on the Order table is to have all the necessary data relevant to an Order in the table, thus avoiding problems if the Client request his data to be deleted, and maintain the original values for that data on the order if the customer data were to change in time.
If you are able to, though, you should not actually delete User data, but have a field in which you specify if the User isActive or isDeleted.