whats the difference between these create methods - ruby-on-rails

Hey I am stuck with my orientation in rails.
I got a User model, a Course Model and a CourseEnrollment Model.
When I want to add a link in my Course Index View like
link_to 'join' CourseEnrollment.create(:course_id => course.id, :user_id => current_user)
Does this create method belong to my Model? I am confused because in my User Model I defined a method that uses role_assignments.create(.....). What is the difference between these 2 create methods? I cant use course_enrollments.create by the way. Thx for your time

I'm a bit confused as to what you're asking, but I'll try my best.
(First of all, in your example, current_user should probably be current_user.id.)
When you call CourseEnrollment.create, you are simply creating a new CourseEntrollment model with the specified attributes.
Assuming that your User model has_many :role_assignments:
When you call #role_assignments.create from within your User model, Rails automatically creates the association for you (e.g. sets the user_id to the id of the user). This doesn't have to be done within the model itself, though:
current_user.role_assignments.create(...) # automatically sets the association
Assuming that your User model also has_many :course_enrollments, the following will create a CourseEnrollment model and automatically associate it with the current user:
current_user.course_enrollments.create(...)

Related

Rails 5 - Best way to hold onto params for creating associations?

Here's the scenario to illustrate my question. I have 2 models:
# models/post.rb
belongs_to :user
validates_presence_of :comment
And we have a devise model called Users
# models/user.rb
has_many :posts
What I would like to achieve:
Person comes to the website, is able to create a Post, after creating the Post, they are prompted to create an account. After creating the account, the Post that they just created would be associated to the User they just created.
Usually i'd make use of routes to hold the params[:id] which can be accessed in the controller method. For example the URL may look something like this:
www.foo.com/foo/new/1
And then I can do this:
# foo_controller.rb
def new
#foo = Foo.new
#parent = Parent.find(params[:id])
end
And in the view I can simply access #parent and use a hidden field to fill the parent ID.
But when routing through so many different pages (such as creating a Devise User), how do I hold onto the parent/child ID such that I can still create that association?
Using an hidden field or the route to store the id, with no authorization in the process, would not be secure. What if I just use the browser inspector and change the value of the id ? Your cool post would be mine.
What you could do is, for instance, add a field called guest_id to the Post, in which the value is unique (like SecureRandom.uuid), and also store that value in the session.
Thus, after the user is created, you could do something like that
if (post = Post.find_by(guest_id: session[:guest_id])).present?
post.update(user_id: current_user.id)
end

How find all the associations of an instance

This question RAILS: How to get has_many associations of a model tells how to find all the associations of a Class. I want to do this for an instance of the class. In particular I have a User model, and when I setup a User instance, it has a number of associations e.g. user.profile, user.plans etc. I want to check all the associations have been successfully set up for a particular user instance. How do you do this?
Based on the link you provided you should be able to accomplish what you want by doing this:
User.reflect_on_all_associations.map { |assoc| assoc.name }.each do |assoc|
association_object = user.send assoc
#note this is the user instance not the class.
# do whatever you want with association_object. check if nil?
end
What the code does, it to iterate through the list of association name keys returned the link you provided and then use it to call the "method" (meaning the association) by using send.
Hope that helps

How to reduce number of calls to a helper method

In my view, I need a User object to display a few different properties. There is an instance variable #comments that's being sent from the controller. I loop through the comments and get the User information through a helper method in order to reduce db calls.
Here is the helper method:
def user(id)
if #user.blank? == false && id == #user.id
return #user
else
return #user = User.find(id)
end
end
And in the view, I display the details as follows:
<h4> <%=user(comment.user_id).name%> </h4>
<p><%=user(comment.user_id).bio%></p>
<p><%=user(comment.user_id).long_bio%></p>
<p><%=user(comment.user_id).email%></p>
<hr>
<p><%=user(comment.admin_id).bio%></p>
<p><%=user(comment.admin_id).long_bio%></p>
<p><%=user(comment.admin_id).email%></p>
I was told that assigning a variable in the view is bad practice and hence I am calling the helper method multiple times instead of assigning the returned User object.
Is there a better way to do this?
I think you are overcomplicating things here.
Let's say you have a user model
class User < ActiveRecord::Base
has_many :comments
end
an admin model
class Admin < User
end
a comment model
class Comment < ActiveRecord::Base
belongs_to :user
end
Now you only need a type column in your users table and you can do things like this:
Admin.all (All users with type "Admin")
User.all (Really all users including type "Admin" and all other types)
and for every comment you can just use
comment.user.bio
and it doesn't matter if it's an admin or not.
See http://www.therailworld.com/posts/18-Single-Table-Inheritance-with-Rails for example
Additional info: To reduce db calls in general(N+1 queries) watch http://railscasts.com/episodes/372-bullet
It's perfectly fine to pass models to your view and build the data on the view off of the data contained in the model. Keep in mind that I'm not entirely certain how you want your page to work, but one option you may have is to use a partial view and pass it the user object. This allows you to still only have the one model in your partial view without setting additional variables.
Also, without knowing what kind of database you're using or if your models have any associations, and assuming that you're doing some input validation, you may not need this helper method and may be able to lean on your ORM to get the user object.
For Example:
<%= comment.user.age %>
This isn't any more efficient than what you've currently got, but it certainly makes the code look cleaner.
Another alternative: set a user variable in the view. You're not performing logic in your view at this point, you're simply storing some data to the heap for later use.

Single Table inheritance with CRUD and forms in Rails

I'm a bit confused about STI in rails.
My situation:
I have a Contact model that has description and data string fields, to store some contact like phone, fax, email, etc.
Now when I have some specific contact type like phone number of email address I want to walidate the data format in different way and I want to make some different formating on output.
I decided to use STI as all the models have the same data with just different behaviour. And I have some questions regarding forms and CRUD operations as I don't want to go against Rails conventions.
How do I make a dropdown list in form with model type? Should I hardcode it or is there some more automated way?
How do I create a record? Should I use switch statement and according to received type create new model of according instance?
How should I update it if I'm going to change the model type? Cast the object to new class? Or create a new object and destroy the previous one?
I'll be very thankfull for your help!
Yes, should do a hardcore as there no default store for your STI models.
Generally, yes. But With Rails you could just use camelize.constantize to get class from string. Another way is just use parent model, and set type field manually. As with STI all records are in the same table and then all are of the parent class.
If you wish to update, just update type field. Then you could re-query to force Rails to get new object of different type.
You could create a model like this :
Type < ActiveRecord::Base
has_many :contacts
end
You could use this command rails g model Type name:string, add a type_id column in your contact and migrate the database.
end change your contact's model like this :
Contact < ActiveRecord::Base
belongs_to :type
end
Now, in your form, you could use this :
select("type", "type_id", Type.all.collect {|t| [ t.name, t.id ] }, { :include_blank => true })
It should resolve your problem.
Now you can do something like this :
#emails = Type.find_by_name('email').contacts
Or use scopes.

How to implement a last_modified_by (person) attribute on two unrelated models - Rails

I have a Record model and in order to edit this model, you must be logged in as an instance of Admin. I would like to have a column called last_modified_by which points to the Admin who last modified the Record. In the database, I was thinking it would be good in the records table to add a column that holds the Admin's id; however, the only way I know how to do that is with an association. These two models are not associated with each other so an association doesn't make a lot of sense. Is there any other way I might be able to accomplish this task without resorting to associations? Any advice would be much appreciated!
Hmm, I think the association is a good tool here. You might want to try to hack it somehow but I think nothing you can conjure up will ever be as good as an association via a foreign_key(also so fast). But perhaps you would like to name your association and do something like:
class Record < ActiveRecord::Base
belongs_to :culprit, :class_name => 'Admin', :foreign_key => 'last_modified_by'
end
or give it some more senseful naming?
You could create an Active Record before_save callback. The callback would save the admin's id into the last_modified_column. This would make sure the admin id is saved/updated each time there is a change to the model.
For example, assuming admin is #admin:
class Record < ActiveRecord::Base
before_save :save_last_modified
def save_last_modified
self.last_modified_column = #admin.id
end
As for getting #admin, you could employ a method similar to this, and set #admin = Admin.current (like User.current in the link) somewhere in the Record model.

Resources