rails polymorphic setup error? - ruby-on-rails

I think I'm supposed to use polymorphic for this, but when I tried the code I could find to solve it, it didn't work.
In plain English, I am creating a Message, and I want it to
1) either belong_to a Guide or a Member
2) has_one Trip or Bid
I get a rollback error when I try and save a new Message and when I try and reference the "first_name" of a Guide in a View via a message I get the following error:
undefined method `guide' for #<Message:0x0000000487bd48>
Did you mean? guide_id
These are my models:
class Guide < ApplicationRecord
has_many :messages, as: :messageable
end
class Member < ApplicationRecord
has_many :messages, as: :messageable
end
class Message < ApplicationRecord
belongs_to :messageable, polymorphic: true
has_one :bid or :trip
end
This is the code snippet for showing the first_name, for what it's worth the text of the message msg.message displays just fine.
<% if #bid.messages.present? %>
<% #bid.messages.each do |msg| %>
<p>From:
<% if msg.guide_id.present? %>
<%= msg.guide.first_name %>
<% elsif msg.member.present? %>
<%= msg.member.first_name %>
<% end %>
</p>
<p>Message: <%= msg.message %></p>
<% end %>
<% else %>
<p>No messages</p>
<% end %>

You always keep referencing the polymorphic name, so instead of doing msg.guide.first_name, you use: msg.messageable.first_name
It might be worth to share your database migration as well. In the code you are checking for: guest_id, which shouldn't be part of the Message model. There should only be an attribute called messagable_id, so the view can be simplified:
<% if #bid.messages.present? %>
<% #bid.messages.each do |msg| %>
<p>From: <%= msg.messageable.first_name %></p>
<p>Message: <%= msg.message %></p>
<% end %>
<% else %>
<p>No messages</p>
<% end %>

Related

List sections with books associated with them

I'm fairly new to ruby on rails and this has been kind of an interesting problem since this seems easy to implement in other languages but I don't know how to tackle it in this one. There was a similar post to this but it had two separate models which I would like to avoid.
This is my end goal:
Section Name
Book A, author
Book B, author
Section Name
Book C, author
Book D, author
Ideally, I'd like to have books be one model, so my model looks like this:
Book Model
class Book < ApplicationRecord
validates :section, :title, :author, presence: true
Book Controller
def index
#books = Book.all
I'm assuming I would need some sort of view that has it list it like below but I'm not sure how to go from there.
<% #sections.each do |section| %>
<% Book.each do |book| %>
<%= book.name %>
<% end %>
<% end %>
Any help would be very appreciated!
Firstly you need migration and associations between these models
change_table :books do |t|
t.belongs_to :section, foreign_key: true, null: false
end
class Book < ApplicationRecord
belongs_to :section
class Section < ApplicationRecord
has_many :books, dependent: :destroy
And in view you can iterate through sections and separately through evert section books
<% #sections.each do |section| %>
<div><b><%= section.name %></b></div>
<ul>
<% section.books.each do |book| %>
<li>
<%= book.name %>, <%= book.author %>
</li>
<% end %>
</ul>
<% end %>
what you need is this:
<% #sections.each do |section| %>
<% section.books.each do |book| %>
<%= book.name %>
<% end %>
<% end %>

Where's the textNode in the view coming from?

# controller
def index
#teams = TeamMember.where(user: current_user)
end
# view
<%= #teams.each do |t| %>
<h2><%= t.project.name %></h2>
<p>Where's the line below this coming from?</p>
<!-- what's happening here? -->
<% end %>
The result in the browser looks as follows. It returns #projects as a string. Where is this coming from and how do I remove it?
ERB
You trigger ERB by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output.
You have used <%= %> for looping projects and the block form of Array#each returns the original Array object, which is why it prints the projects result at the end.
you have to use <% %> for #projects.each do |p| instead of <%= %>
# view
<% #projects.each do |p| %>
<h2><%= p.name %></h2>
<% end %>
Team member Model
class TeamMember < ApplicationRecord
belongs_to :user
belongs_to :project
end
User Model
class User < ApplicationRecord
has_many :team_members
end
Project Model
class Project < ApplicationRecord
has_many :team_members
end
Controller
def index
#teams = current_user.team_members
end
View
<% #teams.each do |t| %> // Remove '=' from the loop itereation
<h2> <%= t.project.name %> </h2>
<% end %>

Displaying User Avatar (without duplicates) for each post in a Collection List with Rails 5

👋 all,
I want to display a list of collections with many posts.
So I call all collections in the controller as:
def index
#collections = Collection.order("RANDOM()")
end
Then in the View:
<% #collections.each do |collection| %>
<%= link_to collection.title, collection %>(<%= collection.posts.count %>)
<!-- Designers (Users) -->
<% collection.posts.each do |post_designer| %>
<!-- I want to display designer avatars in here, I have designer_id from the post, but how do I access Designer table to pull avatar? -->
<%= post_designer.designer_id %>
<% end %>
<!-- Images -->
<% collection.posts.each do |post| %>
<%= link_to image_tag(post.image.thumb.url.to_s, class: "fr"), collection %>
<% end %>
<% end %>
My question is that:
I want to display designer avatars in here instead of designer_id, I have designer_id from the post, but how do I access Designer table to pull avatar?
Thank you!!!! 🙏
Relations:
models/collection.rb
class Collection < ApplicationRecord
belongs_to :designer
has_many :collectivizations
has_many :posts, through: :collectivizations
end
models/collectivization.rb
class Collectivization < ApplicationRecord
belongs_to :post
belongs_to :collection
end
models/post.rb
class Post < ApplicationRecord
belongs_to :category
belongs_to :designer
has_many :collectivizations
has_many :collections, through: :collectivizations
---------------
👍 SOLUTION
It looks like I just an obvious typo error! 🤦‍♂️ The code below works, but it gives dublicates if there is more than 1 post for an user. How can I fix the duplicates?
<% collection.posts.each do |post_designer| %>
<%= link_to image_tag(post_designer.designer.avatar.url.to_s, class: "avatar-small ml1"), post_designer, class: "fl" %>
<% end %>
Try change your code like below. It will fetch first post for designer and you won't see any duplicates for designer.
<% collection.posts.select("DISTINCT ON (designer_id) *").each do |post_designer| %>
<%= link_to image_tag(post_designer.designer.avatar.url.to_s, class: "avatar-small ml1"), post_designer, class: "fl" %>
<% end %>

Rails associations has_many :through

I'm getting started with Ruby on Rails and I have encountered an issue with the has_many :through association.
The models I'm using are:
class Phrase < ActiveRecord::Base
attr_accessible :event_type_id, :template_pieces
belongs_to :event_type
has_many :phrases_pieces
has_many :template_pieces, :through => :phrases_pieces
end
class TemplatePiece < ActiveRecord::Base
attr_accessible :datatype, :fixed_text, :name
has_many :phrase_pieces
has_many :phrases, :through => :phrases_pieces
end
class EventType < ActiveRecord::Base
attr_accessible :name
has_many :phrases
end
class PhrasesPiece < ActiveRecord::Base
attr_accessible :order, :phrase_id, :template_piece_id
belongs_to :phrase
belongs_to :template_piece
end
And I'm trying to create a new phrase, editing its default form to:
<%= form_for(#phrase) do |f| %>
<% if #phrase.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#phrase.errors.count, "error") %> prohibited this phrase from being saved:</h2>
<ul>
<% #phrase.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Select the event type:
<%= collection_select(:phrase, :event_type_id, EventType.all, :id, :name) %>
Select the phrases to be used:
<%= collection_select(:phrase, :template_pieces, TemplatePiece.all, :id, :name) %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I first had an issue with Mass Assignment, but I fixed that adding the attr_accessible :template_pieces to the phrases model. I'm unsure if that is the correct way of fixing it, but at least it stopped complaining that it could not mass assign the protected attribute.
Now, I'm getting the following error when submitting a new phrase:
undefined method `each' for "1":String
Which I kinda think happens due to the fact that there are supposed to be many template_pieces for a given phrase, but I'm currently only able to submit them one at a time. So it just finds the one, tries to iterate through it and fails.
How would I go about fixing that? Is there a better way of entering models with the has_many :through to the database? Do I have to do it manually (as in dismissing the default controller #phrase = Phrase.new(params[:phrase])?
Thanks!
You should use the fields_for helper to wrap the nested attributes:
<%= f.fields_for :template_pieces do |template_f| %>
<%= template_f.collection_select, :event_type_id, EventType.all, :id, :name %>
Select the phrases to be used:
<%= template_f.collection_select, :template_pieces, TemplatePiece.all, :id, :name %>
<% end %>
Reference
fields_for documentation.

Getting specific items from iterating rails 3

I am trying to find a way to pull all notes that are assigned to a course but only when necessary. I have a show page which shows all of the notes for a quiz.
course show.html.erb
<%= #course.name %>
<% #quiz.notes.each do |note| %>
<%= link_to note.title, quiz_note_path(#quiz, note) %><br/>
<% end %>
The above code works find except it pulls all of the notes and not the notes that are assigned to that course. How can I tell rails to only pull the note if note and course name are equal?
update!
In the note new.html.erb I have am using collection_select
<%= f.collection_select(:course_ids, #quiz.courses, :id, :note_name, options = {:prompt => "Choose"}) %>
It seems like you don't have relationship between course and quiz.
A course has many quizzes, a quiz has many notes. You should setup your relationship this way, so it won't pull out unnecessary notes that are not related to the current course.
The trick here is to pull all notes inside a course by using has_many :through.
class Course < ActiveRecord::Base
has_many :quizzes
has_many :notes, :through => quizzes
end
class Quiz < ActiveRecord::Base
has_many :notes
end
class Note < ActiveRecord::Base
belongs_to :quiz
end
<%= #course.name %>
<% #course.notes.each do |note| %>
<%= link_to note.title, quiz_note_path(note.quiz, note) %><br/>
<% end %>
Try something like this.
<%= #course.name %>
<% #quiz.notes.select { |n| n.title == #course.name }.each do |note| %>
<%= link_to note.title, quiz_note_path(#quiz, note) %><br/>
<% end %>
Enumerable.select evaluates the block and returns only the elements for which it was true.

Resources