So a polymorphic relationship that has comments on articles and newsitems, and each comment also belongs to a user. I've made it work so far, it seems, and in the view, this works for printing out the user_id for each comment posted:
<% #comments.each do |comment| %>
<div>
<%= comment.updated_at.strftime("%b %d %Y, %H:%M") %></strong>
</div>
<div>
<%= comment.user_id %>
</div>
<div>
<%= comment.comment %>
</div>
<% end %>
But obviously I'll need to add username/avatar/etc, not the id. How do I access those values?
UPDATE: following mudasobwa's answer.
Models:
class User < ActiveRecord::Base
has_many :comments
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
…and…
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
belongs_to :user
end
Adding <%= comment.user.email %> to the view after that produces:
undefined method `email' for nil:NilClass
UPDATE 2: And in the view, this prints what it is supposed to:
<%= comment.user_id %> | <%= comment.commentable_id %> | <%= comment.commentable_type %>
When retrieving through a polymorphic association, get the associated object using the association name, e.g.:
comment.commentable
Rails will automagically instantiate the class according to the commentable_type:
comment.commentable.class # => User
comment.user comment.user.emailetc. work, as suggested by zetetic in the comments to his answer. It was the nil returns. I was testing it on pages that had other comments created before changing the model, so they didn't have the user attributes assigned to the comments, so Rails was returning nil, leading to the confusion. Removing those comments and posting new ones correctly displays the user's email and username next to the comment on the article page now. Thanks for your help.
Related
Im a real noob at Rails. Im actually a Business Analyst trying to teach myself code so i can work with Devs a lot closer at work. I am having issues with retrieving fields from models.
I have two modals User and CricketClub Adverts, these can be seen below:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
mount_uploader :picture, PictureUploader
#validates_presence_of :picture
#validates_integrity_of :picture
#validates_processing_of :picture
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :cricket_club_advert
has_many :application
end
and
class CricketClubAdvert < ActiveRecord::Base
belongs_to :user, foreign_key: "user_id"
has_many :application
mount_uploader :picture, PictureUploader
end
In my controller I have the following code:
#adverts = User.includes(:cricket_club_advert)
In my view i have the following:
<% #adverts.each do |advert| %>
<!-- Feed Entry -->
<div class="row">
<div class="large-2 columns small-3">
<%= image_tag(advert.picture_url) %>
</div>
<div class="large-10 columns">
<h4> <%= link_to advert.cricket_club_advert.title, cricket_club_advert_path(advert.cricket_club_advert.id) %></h4>
<%= truncate(strip_tags(advert.cricket_club_advert.description), length: 250) %>
<ul class="inline-list">
<li>More</li>
</ul>
</div>
</div>
<hr>
<!-- End Feed Entry -->
<% end %>
According to the documentation I have used the calls right, but i get this error:
undefined method `title' forCricketClubAdvert::ActiveRecord_Associations_CollectionProxy:0x007feca33270c0>
I cant figure out what i am doing wrong.
What you really do here is you're iterating over users and its adverts. So your variable name is quite misleading, it should be:
#users = User.includes(:cricket_club_adverts)
and in your view:
<% #users.each do |user| %>
# ...
# ... here the iteration over adverts starts:
<% user.cricket_club_adverts.each do |advert| %>
# ...
<% end %>
# ...
<% end %>
BTW note the plural form - if you use has_many association, you should name your assiciations in plural.
Instead of :
#adverts = User.includes(:cricket_club_advert)
Use :
#adverts = User.includes(:cricket_club_adverts)
Because, one user has got many cricket_club_adverts (has - many relation)
first_advert = #adverts.first
cricket_advert = first_advert.cricket_club_adverts.first
#as one user can have many cricket_club_adverts and each
#cricket_club_advert will have title, id, description attributes.
hence title, id, description can be fetched by:
cricket_advert.title #fetch the title
cricket_advert.id #fetch the id
cricket_advert.description # fetch the description.
I am building a login system that has two users, buyer and seller, in Rails 4.0.4.
For auth I am using the Devise gem: https://github.com/plataformatec/devise
To create a new buyer I use the route buyer/new. However, the fields for the user do not show in the view. I also using debug to show #buyer.user in the view and it has been created. But when I call f.fields_for #buyer.user do |u| the loop is never entered.
Any ideas of why this is? Also, the polymorphic associations seem to be working in the rails console.
Buyer Controller:
# GET /buyers/new
def new
#buyer = Buyer.new
#buyer.build_user
end
Buyer Model
class Buyer < ActiveRecord::Base
has_one :user, as: :role
accepts_nested_attributes_for :user
end
Buyer/new View
<%= form_for(#buyer) do |f| %>
....
<div class="field">
<%= debug(#buyer.user) %>
<% f.fields_for #buyer.user do |u| %>
<%= u.text_field :email %>
<% end %>
</div>
User Model
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :role, polymorphic: true
Shouldn't you have an = on the fields_for? http://rubydoc.info/docs/rails/ActionView/Helpers/FormHelper:fields_for
E.G.
<%= f.fields_for #buyer.user do |u| %>
I have a friendship model that is working but when I include this code in my user/show view, I get this unwanted result:
Friends
Dave Olson, accepted
[#<Friendship id: 74, user_id: 1, friend_id: 2, status: "accepted", created_at: "2014-03-27 03:54:08", updated_at: "2014-03-27 03:54:09">]
I can't figure out why the extra Hash prints out.
Here's the code from my view:
<h3>Friends</h3>
<%= #user.friendship.each do |friendship| %>
<p><%= friendship.friend.name %>, <%= friendship.status %></p>
<% end %>
The User model is:
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_many :items
has_many :friendship
end
And the relevant portion of my Friendship Model:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: "User", foreign_key: "friend_id"
validates_presence_of :user_id, :friend_id
....more code
end
The only way I have been able to eliminate the hash is by not running the block. Unfortunately that isn't going to work. So, why is the hash printing out? I have tried searching for an answer but haven't had any success. Any help would be greatly appreciated.
Remove the equals sign = from the erb scriptlet used in the each loop:
<h3>Friends</h3>
<% #user.friendship.each do |friendship| %>
<p><%= friendship.friend.name %>, <%= friendship.status %></p>
<% end %>
The reason you see the unwanted hash is because <%= as opposed to <% is used to print the output. So, <%= #user.friendship.each... prints the result returned by that each block.
Simply put
This tag will output something
<%= ... %>
This tag will not
<% ... %>
I have a problem with my application, crash when I put the path student_postulations_path in the navbar :S.
I have in my route.rb
resources :students do
resources :postulations
end
and my application say this error
No route matches {:controller=>"postulations"}
My view
<% elsif student_signed_in? %>
<% menu_group :pull => :right do %>
<%= menu_item "Postulaciones", student_postulations_path %>
<%= menu_divider %>
<%= drop_down current_student.email do %>
<%= menu_item "Logout", destroy_student_session_path, :method => :delete %>
<% end %>
<% end %>
<% else %>
when I use rake routes:
student_postulations GET /students/:student_id/postulations(.:format) postulations#index
POST /students/:student_id/postulations(.:format) postulations#create
new_student_postulation GET /students/:student_id/postulations/new(.:format) postulations#new
edit_student_postulation GET /students/:student_id/postulations/:id/edit(.:format) postulations#edit
student_postulation GET /students/:student_id/postulations/:id(.:format) postulations#show
PUT /students/:student_id/postulations/:id(.:format) postulations#update
DELETE /students/:student_id/postulations/:id(.:format) postulations#destroy
My models student and postulation:
class Student < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :nombre, :rol,
:prioridad, :resumen, :categoria, :foto
# attr_accessible :title, :body
has_many :postulations
end
class Postulation < ActiveRecord::Base
attr_accessible :status, :student_id
belongs_to :student
end
I dont understand my error... I thing have all right. Please help! :).
Thank
In nested resource routing you are getting
student_postulations GET /students/:student_id/postulations(.:format)
So in your view you need to pass the #student object with student_postulations_path(#student)
The helpers like student_postulations_path, student_postulations_url take an instance of Student as the first parameter student_postulations_path(#student) to find the record of student .
You can get more info from the guide
So your link path will be
<%= menu_item "Postulaciones", student_postulations_path(current_student) %>
I have a Post model:
class Post < ActiveRecord::Base
attr_accessible :title, :content, :tag_names
belongs_to :user
has_many :comments, :dependent => :destroy
end
belongs_to :post, :counter_cache => true
belongs_to :user
end
a User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :avatar, :subscribed_tag_names
has_many :posts, :dependent => :destroy
has_many :comments, :dependent => :destroy
end
and a Comment model:
class Comment < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :post, :counter_cache => true
belongs_to :user
end
This is how I show the user who created the post in the index.html.erb view:
<% #posts.each do |post| %>
<div id="post-<%= post.id %>" class="post">
<h3 class="post-title"><%= link_to post.title, post %></h3>
<div class="post-author">
<span class="profile-picture">
<%= image_tag post.user.avatar.url(:thumb) %>
</span>
<span class="post-author-name">
<strong><%= link_to post.user.username, post.user %></strong>
</span>
</div>
(etc...)
How to display the user who last commented the post (as you can see in StackOverflow and various forums)?
<% comment = post.comments.order(:created_at).reverse_order.first %>
<%= comment.user.email if comment %>
This does the following:
it get all comments of the post, ordered by the created_at field in reverse order (i.e. the largest value on top). From that, it selects the first value, i.e. the newest comment. From that comment, you then get the user.
Setting the order is non-optional as databases are free to return elements in an arbitrary order if it is not specified explicitly. You will observe the random order more often on Postgres or Oracle than on MySQL or SQLite because of the way they store records. However, all of them will return random element orders at least occasionally if the order is not specified.
The previous answer only works when your post has some comments. When there are no comments then you will receive an error, as you have noted.
You could solve this by simply testing that comments exist before trying to output it:
<% #posts.each do |post| %>
...
<% if post.comments.empty? %>
Nobody has commented yet
<% else %>
<%= post.comments.last.user.email %>
<% end %>
<% end %>
<% #posts.each do |post| %>
...
<%= post.comments.last.user.email %>
<% end %>