anonn023432
anonn023432

Reputation: 3120

Inconsistent rails method `exists` and `any?`

I'm working on a Ruby on Rails based chat. So I initially create a conversation between 2 clients when they add each other as friends and my model for Conversation is as follows:

class Conversation < ActiveRecord::Base
  has_many :messages
  belongs_to :player_client
  belongs_to :client
end

Now when the player_client clicks a specific button I want to create an automated message for them. This should only happen if they've never sent a message to each other i.e. the conversation has no associated messages.

Trying the following methods from the console:

@conversation = Conversation.find(7)
@conversation.messages.any?
> False
@conversation.messages.empty?
> True
@conversation.messages.exists?
> False

Which are all expected values. But adding any of these methods in my Rails code throws an error:

NoMethodError (undefined method `messages' for #<Conversation::ActiveRecord_AssociationRelation:0x007fa187ca1ec8>)`

Which I guess is showing up because messages don't exist for that conversation so it can't find any association for that conversation. I'm not sure why this method would be inconsistent though.

EDIT: Adding the error causing code.

conversation_with_player_client = @client.conversations.select{|c| c.player_client_id == @game.player_client.id}

if conversation_with_player_client.count == 0
  @conversation = @client.conversations.build({player_client_id: @game.player_client.id})
  @conversation.save!
else
  @conversation = @client.conversations.where({ player_client_id: @game.player_client.id })
end

puts "the conversation we found was #{@conversation.inspect}"
# This gives the response
# #<Conversation id: 7, player_client_id: 1, client_id: 11, created_at: "2018-02-12 20:55:55", updated_at: "2018-02-12 20:55:55">
# in the console so it can get the conversation 

if @conversation.messages.any?

# this line is causing the error

Upvotes: 0

Views: 77

Answers (4)

Hamdi Bayhan
Hamdi Bayhan

Reputation: 1833

The another way with find_or_create_by method:

@client.conversations.find_or_create_by(player_client: @game.player_client.id)

To find more info:

https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by

Upvotes: 0

Mitch
Mitch

Reputation: 546

That error is due to you calling messages on a collection of conversations rather than a single conversation.

I'd be willing to bet the offending code is something like:

client.conversations.messages #=> NoMethodError

Instead, it should be:

client.conversations.first.messages

EDIT - this is the line causing the error:

@conversation = @client.conversations.where({ player_client: @game.player_client.id })

where will return a relation representing many conversations. If you only want a single conversation, you can use find_by:

@conversation = @client.conversations.find_by({ player_client: @game.player_client.id })

Upvotes: 2

Pablo
Pablo

Reputation: 3005

In your code:

@conversation = @client.conversations.where({ player_client: @game.player_client.id })

is not a conversation. Is more than one. You cannot use messages there.

If you need only one conversation, you must change where by find_by.

If not, you need to iterate through all conversations.

Upvotes: 0

Ronan Lopes
Ronan Lopes

Reputation: 3398

Did you tried with present? method? Guess it would work better... like this:

@conversation.messages.present?

It will return false if messages is nil or empty, so I guess it fits better. Good luck!

Upvotes: 0

Related Questions