Do associations work both ways?

This may seem like a real simple question, but do associations work both
ways?

I have a user model with, has_many :posts
I have a post model with, belongs_to :user

My posts controller has

@posts = Post.all

and my view does a ‘@posts.each do |post|’ loop

In that loop, can I do:

<% post.user %>

…to give me back the user that made that post?

In the rails console I can do user.posts (that gives me all the posts a
user has made) but I can’t do post.user (to give me the user).

I can do post.user_id which gives me the user_id, but I want their name
not their user_id - perhaps with something like post.user.name :confused:

Am I doing something wrong? I thought one of the benefits of
associations like this was so we wouldn’t have to do separate queries?
Sorry if this is a silly question - I’m a Rails nube.

Thanks in advance!

On Dec 12, 6:38pm, Ast J. [email protected] wrote:

In that loop, can I do:

<% post.user %>

…to give me back the user that made that post?

In the rails console I can do user.posts (that gives me all the posts a
user has made) but I can’t do post.user (to give me the user).

As long as you have that belongs_to, post.user should work. What do
you mean when you say that you can’t?

Fred

Hi Fred, thanks for the reply.

In the rails console with ‘post.user’ I get:

NoMethodError: undefined method `user’ for #Post:0x00000101455590

And in my view 'post.user.nameI get:

undefined method `name’ for nil:NilClass

If I leave off ‘.name’ I get what looks like an object:

User:0x000001031f4470

Hi Rodrigo, thanks for the reply.

I’ve tried that - but still doesn’t work :frowning:

I pushed the app to git:

https://github.com/Brook/uf/blob/master/app/views/topics/index.html.erb

And you can see where I’m trying to call it on line 18

Maybe you can spot where I’ve gone wrong? :confused:

It’s not normal
try reboot your server

check in DB if user_id is null

try Post.first.user.name

2010/12/12 Ast J. [email protected]

If I leave off ‘.name’ I get what looks like an object:
To unsubscribe from this group, send email to

[email protected][email protected]

.
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.


Rodrigo M.
(62) 8567-3142

Search in app/model for the file User.rb (in singular)

This file exists??

Paste the code of this file here.

2010/12/12 Ast J. [email protected]

Maybe you can spot where I’ve gone wrong? :confused:
.
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.


Rodrigo M.
(62) 8567-3142

Thank you both for your help - I got it fixed with a little help from
Isaackearse on the Rails IRC channel.

The reason it was playing up was because I had some posts in the db that
weren’t associated to any users - once they were deleted everything
works as expected :slight_smile:

Thanks again to everyone for their help :smiley:

2010/12/12 Rodrigo M. [email protected]:

Search in app/model for the file User.rb (in singular)
This file exists??

For posterity that should be user.rb not User.rb of course

Colin

Great!!

when user_id is null (and can be null in some cases)

you can do this

<%post.each do |p|%>
<%=p.user.name unless p.user.nil?%>
<%end>

other way is

<%=p.user.name unless p.user.empty?%>

2010/12/12 Colin L. [email protected]

“Ruby on Rails: Talk” group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to

[email protected][email protected]

.
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.


Rodrigo M.
(62) 8567-3142

No, no, if field is null or empty you can use this.

It’s not specifc for join or association

You are learning the ROR, and is better for you use .empty?

It’s will cause less errors for you

Sorry for my english… i’m still learning =D

2010/12/12 Ast J. [email protected]

You received this message because you are subscribed to the Google G.
“Ruby on Rails: Talk” group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to

[email protected][email protected]

.
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.


Rodrigo M.
(62) 8567-3142

Thanks again Rodrigo, and no worries about your English… it is very
good!

If you’re on twitter, please feel free to add me :slight_smile: my username is:
AstonJ

Thanks Rodrigo.

Is that only for db fields that are part of the ‘join’/association?
Because I had some other fields that were empty too (but they belonged
to the post model) but they didn’t cause any probs.

On Dec 12, 2010, at 4:59 PM, Rodrigo M. wrote:

other way is

<%=p.user.name unless p.user.empty?%>

Or, you can push that into the model and avoid the extra logic in the
view:

class Post
def user_name
self.user ? self.user.name : “(none)”
end
end

<% @posts.each do |post| %>
<%= post.user_name %>
<% end %>

You could name the method something like “author_string” or “by_line”,
too. The idea is to keep the view very clean. You might be able to
simply delegate :name, :to => :user in your Post model, but that
would have given you the same problem if the post.user_id referred to
a non-existent User.

-Rob


Rodrigo M.
(62) 8567-3142

Rob B.
[email protected] http://AgileConsultingLLC.com/
[email protected] http://GaslightSoftware.com/

Rob B. wrote in post #968091:

On Dec 12, 2010, at 4:59 PM, Rodrigo M. wrote:

other way is

<%=p.user.name unless p.user.empty?%>

Or, you can push that into the model and avoid the extra logic in the
view:

class Post
def user_name
self.user ? self.user.name : “(none)”
end
end

<% @posts.each do |post| %>
<%= post.user_name %>
<% end %>

Why would you do that, though? Sure, it keeps a little bit of method
chaining out of the view, but at the cost of a completely unnecessary
model method.

If a calculation were being performed to get this value, I’d agree with
defining a method. But I think accessor method chaining in the view is
generally acceptable, particularly when it simply involves traversing
already loaded associations.

You could name the method something like “author_string” or “by_line”,
too. The idea is to keep the view very clean.

Method chaining is much cleaner than this IMHO.

You might be able to
simply delegate :name, :to => :user in your Post model, but that
would have given you the same problem if the post.user_id referred to
a non-existent User.

delegate seems smelly in this context.

-Rob

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Dec 13, 2010, at 2:40 PM, Marnen Laibow-Koser wrote:

class Post
chaining out of the view, but at the cost of a completely unnecessary
model method.

If a calculation were being performed to get this value, I’d agree
with
defining a method. But I think accessor method chaining in the view
is
generally acceptable, particularly when it simply involves traversing
already loaded associations.

But I will remind you that the OP found that the problems came from
Posts that did not have an associated User. In such cases, post.user
will be nil and nil.empty? does not exist. Perhaps you meant to say
unless post.user.blank?, but if there are many places where a
post.user_name is used, the extra method avoids Law of Demeter
violations. (Or “Suggestion of Demeter” if you prefer.)

-Rob

would have given you the same problem if the post.user_id referred to
http://www.marnen.org
To unsubscribe from this group, send email to
[email protected]
.
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
.

Rob B.
[email protected] http://AgileConsultingLLC.com/
[email protected] http://GaslightSoftware.com/

On 13 December 2010 19:40, Marnen Laibow-Koser [email protected]
wrote:

class Post
chaining out of the view, but at the cost of a completely unnecessary
model method.

The method DRYs up the code by not having to repeat
self.user ? self.user.name : “none”
wherever user name is to be displayed. Also it means the text to be
used when there is no user is defined in the model rather than being
scattered around the views.

Colin

Colin

Thanks for the replies Rob and Marnen - they are both very helpful to me
as a nube :slight_smile:

Rob B. wrote in post #968133:

On Dec 13, 2010, at 2:40 PM, Marnen Laibow-Koser wrote:

class Post
chaining out of the view, but at the cost of a completely unnecessary
model method.

If a calculation were being performed to get this value, I’d agree
with
defining a method. But I think accessor method chaining in the view
is
generally acceptable, particularly when it simply involves traversing
already loaded associations.

But I will remind you that the OP found that the problems came from
Posts that did not have an associated User. In such cases, post.user
will be nil and nil.empty? does not exist.

Right you are. I committed the cardinal sin of not considering what you
wrote in light of the whole thread. Sorry.

Perhaps you meant to say
unless post.user.blank?, but if there are many places where a
post.user_name is used, the extra method avoids Law of Demeter
violations. (Or “Suggestion of Demeter” if you prefer.)

I’m aware of that. I don’t think the Law of Demeter is particularly
helpful in Ruby.

-Rob

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Sent from my iPhone

On 13 December 2010 16:30, Rob B. [email protected]
wrote:

Or, you can push that into the model and avoid the extra logic in the view:
class Post
def user_name
self.user ? self.user.name : “(none)”
end
end

Instead of creating a new method to delegate from the associated
object, I rather overload the association with a blank object if a
legitimate associated object is missing, which has the benefit of
allowing me to still use method chains in my views, but to also set
default values for missing objects:

alias_method :activerecord_user, :user
def user
activerecord_user || User.new(:name => “(none)”)
end

There are a few gotchas… most of which I avoid by creating a new
“User”, but not assigning it as an association (more object
instanciation, but if it was a real problem, I could assign it to an
instance variable…). As a balance between reducing the checks in the
view and creating (potentially) confusing methods, it does the job on
occasion.