I'm writing my first app in Ruby on Rails (I've only went through railstutorial.org before ) which is simple Electronic Prescription Service and I run on one thing I can't cope with.
I want to create form for adding new prescription as well as adding some medicines which belong to this newly created prescription.
First problem is - how can I actually add medicines to the prescription when during filling the form prescription doesn't exist yet? What I did before was I first create prescription with #user.prescription.create(presc_attributes) and later #prescription.relations.create(medicine_id).
Now I need to do this probably on one form sending the whole thing using one button ( one HTML request, am I right? ) unless you guys have got better idea. I'm also struggling with an idea where to actually put method creating this prescription. Should it be in PrescriptionController#new or maybe connected to RelationsController#new as well?
I've read couple of articles about nested fields_for but they don't seem to match exactly what I need.
Im really new to RoR so sorry if I missed something important.
Here is my EER as well
http://i.stack.imgur.com/sa9CB.png
UPDATE---
ahhh i see, I think what you want is a relationship with an inverse_of.
If you are using a belongs_to on the join model, it is a good idea to set the :inverse_of option on the belongs_to, which will mean that the following example works correctly (where tags is a has_many :through association):
#post = Post.first
#tag = #post.tags.build name: "ruby"
#tag.save
The last line ought to save the through record (a Taggable). This will only work if the :inverse_of is set:
class Taggable < ActiveRecord::Base
belongs_to :post
belongs_to :tag, inverse_of: :taggings
end
If you do not set the :inverse_of record, the association will do its best to match itself up with the correct inverse. Automatic inverse detection only works on has_many, has_one, and belongs_to associations.
FROM http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Related
I'm using the paper_trail-association_tracking gem to save PaperTrail versions for AR associations. I have a model, let's call it User, that has many Groups and has many Skills. Both of these associations have join tables (user_groups and user_skills). So my User model has two has_many :through associations. All of the models (User, Group, Skill, UserSkill, UserGroup) have PaperTrail enabled on them.
class User < ApplicationRecord
has_paper_trail
has_many :groups, through: user_groups
has_many :user_groups
has_many :skills, through: user_skills
has_many :user_skills
end
Say I want to reify an earlier version of the User model, along with their Skills (user_skills records), but not revert to an earlier version of the user's Groups (user_groups). The code looks something like this:
me = User.find(1)
older_me = me.versions.last.reify(has_many: true)
older_me.save
This will reify both UserGroups and UserSkills for this User, but I want it to reify just UserSkills. It seems the gem will reify all associations automatically, based on this source code I looked through.
So is there a way to specify which association I want to be reified? Or is it not best practices to do this? For my use case, I can't see a problem with this unless the user itself was actually deleted or something like that.
Sorry my models here sound kinda weird, I tried to use something generic and simplified, my real use case and models are a bit complex but this question demonstrates the bottom line of my issue.
I'm trying to generate a one-to-many relationship between users and advice. One user can have many advices.
rails g model User
rails g model Advice user:references
I noticed that this doesn't automatically generate the line has_many :advices in the user.rb file. However, in the advice.rb file, the line belongs_to :user was auto-generated.
In the rails console, I am still able to create multiple Advices for one user without an error.
My question is, is the has_many :advices line necessary in the user.rb file? If not, then why do the Rails guides recommend it?
The has_many association tells Rails that the objects are related and adds methods to the object for querying the associated objects. You could live without it, but it makes things easier.
See the first chapter here:
http://guides.rubyonrails.org/v2.3.11/association_basics.html
Another reference:
https://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many
When you use one-to-many associations you are telling your User model that he has zero or more instances of the model Advice, while Advice belongs to only one model User and its reference to it.
This is how your models should be:
class User < ApplicationRecord
has_many :advices
end
class Advice < ApplicationRecord
belongs_to :user
end
Even if you don't need to declare it right now, you might need it in a long run, so it is always better to have it set. You can read more about this topic here.
I have two models that are associated via a has_many relationship. E.g.
class Newspaper < ActiveRecord::Base
has_many :articles
end
class Article < ActiveRecord::Base
belongs_to :newspaper
validates :uid, presence: true,
uniqueness: { case_sensitive: true }
end
A newspaper is updated several times a day but we only want to construct and add articles to the association that do not already exist. The following code was my first cut of achieving this.
new_articles.each do |article|
unless newspaper.articles.exists? uid: article.uid
newspaper.articles.build(uid: article.uid)
end
end
The newspaper object is either new and unsaved, or retrieved with existing relationships at this point.
My tests indicate that I am able to add two articles to the newspaper that have the same UID using the code above and this is obviously not want I want.
I appears to me that my current code will result in a validation failure upon being saved as the validation looks at uniqueness across the entire articles table and not the association.
What I'm struggling to understand is how the exists? method behaves in this scenario (and why it's not saving my bacon as I planned). I'm using FactoryGirl to build a newspaper, add an article and then simulate an update containing an article with the same uid as the article I've already added. If the code works I should get only one associated article but instead I get two. Using either build or create makes no difference, thus whether the article record is already present in the database does not appear to change the outcome.
Can anyone shed some light on how I can achieve the desired result or why the exists? method is not doing what I expect?
Thanks
The association exists? actually creates a scoped query, as per the association. This is why your existing articles filter doesn't work.
unless newspaper.articles.exists? uid: article.uid
# `articles.exists?` here will produce this if the newspaper is new
# ... WHERE "articles"."newspaper_id" IS NULL AND "articles.uid" = '<your uid>'
# and this, if the newspaper is persisted (with an id of 1)
# ... WHERE "articles"."newspaper_id" = 1 AND "articles.uid" = '<your uid>'
The case of the new newspaper is clearly wrong, as it would only return articles with a nil newspaper ID. But the persisted case is probably undesirable as well, as it still unnecessarily filters against newspaper ID, when you real concern here is that the UID is unique.
Rather, you probably want simply against Article, rather than scoping the exists? through the association, like:
unless Article.exists? uid: article.uid
Concerning your other problem:
this appears to be a FactoryGirl problem where the create method isn't creating db entries in the same way I can in the irb.
FactoryGirl.create should still abide by validations. It might help to see your test.
I'm migrating an application over to ROR from PHP that defines an object, let's call it a Document that can be created by a User who is either a registered user of the application, or an anonymous user who only gives their email address (in this case without an associated User account). There is no requirement for a visitor to create a User account, but they should still have the ability to create a Document.
In my model, I am first led to create the Document model that references the user with a belongs_to association. This however is not always the case. In pure SQL and PHP this is not hard, although it comes with it's own challenges, but I would like to model this in the "purest" Ruby/Rails way.
If a visitor does not have an associated User, their email address will be stored directly against the Document object.
To start the discussion, here are the snippets for each model.
# user.rb
class User < ActiveRecord::Base
has_many :documents
end
# document.rb
class Document < ActiveRecord::Base
attr_accessible :title, :description, :email_address
belongs_to :user
end
My goal is to be able to retrieve all user documents using the standard dot notation:
user.documents
And to also check for the reverse relationship to see if the document belongs to a User or if it contains an email address.
if document.user.nil? ...
if document.email_address.nil? ...
I have read up on the has_one relationship but am not sure if this is the right path to go down.
Any help or suggestions would be appreciated, thanks!
You might want to consider making the User class more flexible so it supports anonymous users and only stores the email address.
It might make your code a bit cleaner.
Greetings,
I have an application where Companies and Users need to belong to each other through a CompanyMembership model, which contains extra information about the membership (specifically, whether or not the User is an admin of the company, via a boolean value admin). A simple version of the code:
class CompanyMembership < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
class Company < ActiveRecord::Base
has_many :company_memberships
has_many :users, :through => :company_memberships
end
class User < ActiveRecord::Base
has_many :company_memberships
has_many :companies, :through => :company_memberships
end
Of course, this makes it simple to get all the members of a company via company.users.all, et al. However, I am trying to get a list of all Users in a Company who are admins of that Company (and also to test whether a user is an admin of a given company). My first solution was the following in company.rb:
def admins
company_memberships.where(:admin => true).collect do |membership|
membership.user
end
end
def is_admin?(user)
admins.include? user
end
While this works, something feels inefficient about it (it's iterating over each membership, executing SQL each time, right? Or is Relation smarter than that?), and I'm not sure if there's a better way to go about this (perhaps using scopes or the fancy new Relation objects that Rails 3 uses?).
Any advice on the best way to procede (preferably using Rails 3 best practices) would be greatly appreciated!
I believe I was going about this the wrong way, specifying conditions on company_memberships instead of users, which was what I actually wanted (a list of Users, not a list of CompanyMemberships). The solution I think I was looking for is:
users.where(:company_memberships => {:admin => true})
which generates the following SQL (for company with ID of 1):
SELECT "users".* FROM "users"
INNER JOIN "company_memberships"
ON "users".id = "company_memberships".user_id
WHERE (("company_memberships".company_id = 1))
AND ("company_memberships"."admin" = 't')
I'm not sure yet if I'll need it, but the includes() method will perform eager loading to keep down the number of SQL queries if necessary:
Active Record lets you specify in
advance all the associations that are
going to be loaded. This is possible
by specifying the includes method of
the Model.find call. With includes,
Active Record ensures that all of the
specified associations are loaded
using the minimum possible number of
queries.queries. RoR Guides: ActiveRecord Querying
(I'm still open to any suggestions from anyone who thinks this isn't the best/most effective/right way to go about this.)
An even cleaner way would be to add an association to your Company model, something like this:
has_many :admins, :through => :company_memberships, :class_name => :user, :conditions => {:admin => true}
You might have to dig into the rails doc to get the exact syntax right.
You shouldn't need :include, unless you have other classes associated with :user that you might reference in your view.
How about something like this:
Company.find(:id).company_memberships.where(:admin => true).joins(:user)
I stumbled across this answer and believe that nowadays there is a nicer way using has_many association scopes (has_many documentation):
has_many :admins, -> { where(admin: true) }, through: :company_memberships, class_name: :user
The second parameter of a has_many association can be a proc or lambda that contains your filter.
I made the activerecord_where_assoc gem to do this.
With it, no need for joins or includes. Doing eager loading remains your choice, not an obligation.
users.where_assoc_exists(:company_memberships, admin: true, company_id: #company.id)
The question is unclear on how to filter the company, so I added it myself. Without this, if a user can be in multiple company, it being admin in one company could mean being treated as an admin in another company.
The gem doesn't work in Rails 3, but we are 9 years later and Rails 4.1 and more are supported.
Here are the introduction and examples. Read more details in the documentation.