I've got the following models in my Rails app:
class Post < ActiveRecord::Base
belongs_to :user
has_many :pictures, :dependent => :destroy
end
class Picture < ActiveRecord::Base
belongs_to :post
has_many :comments
has_attached_file :image, styles: { medium: "800x800>", thumb: "225x225#" }
validates_attachment_content_type :image, :content_type => ["image/jpg","image/jpeg","image/png"]
end
So a Post has_many Pictures. On my Post#index view, I use the following code to iterate through the posts and display the thumbnail for each of their pictures:
<% #posts.each do |post| %>
<% post.pictures.each do |picture| %>
<li>
<%= link_to image_tag(picture.image.url(:thumb)), picture_path(picture)%>
</li>
<% end %>
In order to limit the number of pictures displayed on each page, I'm attempting to implement pagination by using the following code in my Posts controller:
#pictures = #posts.pictures.paginate(:per_page => 5, :page => params[:page])
This gives the following error:
undefined method `pictures' for #<Post::ActiveRecord_Relation:0x007fc960f698a8
What am I doing wrong here? How could I fix this?
Also, I know it seems like it would be easier to just use the Pictures#index page, but I need this to work for other reasons.
Thanks!!
#posts is a relation (array-like object), and it doesn't have a method named pictures.
I'm not sure why you are paginating the pictures attached to each post on an index view, but you might be doing a carousel or something, so it may be valid, but if that's the case, you'll need to paginate in the view (or build a more complex data structure in your controller):
<% #posts.each do |post| %>
<% post.pictures.paginate(:per_page => 5, page => params["post_#{post.id}_pictures_page"]).each do |picture| %>
<li>
<%= link_to image_tag(picture.image.url(:thumb)), picture_path(picture)%>
</li>
<% end %>
<% end %>
Related
👋 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 %>
I have three models
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Movie < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class TV < ActiveRecord::Base
has_many :comment, :as => :commentable
end
While in my home page, people are able to see top comments like a comment's index page.
I currently doing like below, but it is not work
<div>
<% #comments.each do |comment| %>
<%= simple_format comment.content %>
<%= link_to comment.commentable_id %>
<% end %>
</div>
It seems I missed something. What should I add to make it possible to link to parent's show page through the comment?
That is, for example, someone comment "This movie is awesome" on a movie, Transformer.
People are also able to see the comment on comment's index page. Then there is a link bring them to Transformer's show page so that user are able to see more details.
Do I need to do anything on controller as well?
figure it out
just edit like below
<div>
<% #comments.each do |comment| %>
<%= simple_format comment.content %>
<%= link_to **"LINK", comment.commentable** %>
<% end %>
</div>
I have been trying to refactor this code to reduce the db calls by possibly using "includes". I would like to replace the three nested loops in the view. Tried various options but got stuck... I'm still getting familiar with active record querying.
How can I make this more efficient with less queries?
Is using includes the best option?
If so, how do I access the various fields through my HABTM relationships?
Thanks.
Models:
class Category < ActiveRecord::Base
has_many :pub_types
end
class PubType < ActiveRecord::Base
belongs_to :category
has_and_belongs_to_many :issues
end
class Issue < ActiveRecord::Base
has_and_belongs_to_many :pub_types
has_many :images, :dependent => :destroy
end
Controller:
def home
#categories = Category.all
#issues_and_pubs = Issue.joins(:pub_types).uniq
end
View:
<% #categories.each do |category| %>
<%= category.name %>
<% #issues_and_pubs.where(:pub_types => {:category_id => ["#{category.id}"]}).each do |issue| %>
<% issue.images.each do |img| %>
<% if img.featured == true %>
<%= cl_image_tag img.image, :width => 295, :height => 155, :alt => img.name, :crop => :fill %>
<%= link_to issue.name, issue %>
<% end %>
<% end %>
<%= issue.issue_date.try(:strftime, "%B %d, %Y") %>
<%= issue.pub_types.map(&:name).join(", ") %>
<% end %>
<% end %>
Try this instead.
Add this to Category:
has_many :issues, through: :pub_types
Controller:
#categories = Category.includes(:issues => :images)
View:
#categories.each do |category|
category.issues.each do |issue|
issue.images.each do |image|
issue.pub_types # might still result in N+1, haven't tested
On the note above about N+1 on pub_types, I have had occasions where I've eager loaded associations, but Rails has not taken them into account when calling from children to parents. One approach I've used in the past is to be explicit with the references:
Category.includes(:issues => [:pub_types, :images])
Without the has_many through:, this would look rightly peculiar:
Category.includes(:pub_types => [:issues => [:pub_types, :images]])
I'm building an open-source spreadsheet application. So far, its a rails application that has 4 models: table, row, column, and item.
Here is what they look like:
Table.rb:
has_many :columns
has_many :rows
accepts_nested_attributes_for :columns
Column.rb
belongs_to :table
has_many :items
Row.rb
belongs_to :table
has_many :items
accepts_nested_attributes_for :items
Item.rb
belongs_to :row
On the page where you add a new row. You should be presented with something like this:
So the columns are already set, so now you are adding new items which when inserted should include the row_id, column_id, and value for each item.
So far my form looks like this:
<%= nested_form_for [#table, #row] do |f| %>
<% #columns.each do |column| %>
<%= column.name %> <br>
<%= f.fields_for :items do |item_form| %>
<%= item_form.text_field :value %>
<% end %>
<% end%>
<%= f.submit %>
<% end %>
I'm using the nested_form for the nested forms. But so far, I can't get a textbox for the item's value to show up. Also, is this the best way to get what I want (like the picture), or is there a cleaner way?
Thanks for all help!
You'll need to build at least 1 item for fields_for to render anything. Try doing this in your new controller action.
def new
...
#row.items.build
end
This should be somewhat simple but cant seem to grasp the association.
I am using nested_form and paperclip. I have a model called photo to store all images and a post model. I am trying to show the photos associated to the relevant post but am getting 'undefined method avatar' when rendering the view.
class Post < ActiveRecord::Base
has_many :photos, :dependent => :destroy
accepts_nested_attributes_for :photos
attr_accessible :title, :comments, :photo_id, :avatar, :photos_attributes
end
Class Photo < ActiveRecord::Base
belongs_to :post
attr_accessible :avatar, :post_id
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
Controller
def new
#post = Post.new
#post.photos.build
end
So i am under the impression that when a post gets built an association between the Post and Photo model is made? is that right?
So when i call this in the view i get the undefined method, can anyone advise where I am going wrong please
<% #posts.each do |f| %>
<ul>
<li><%= f.title %></li>
<li><%= f.department.name %></li>
<li><%= image_tag f.avatar.url(:thumb) %></li>
<li><%= link_to "Delete Post", post_path(f.id), :confirm => "Are you sure?", :method => :delete %></li>
</ul>
<% end %>
I have tried
<%= image_tag f.photo.avatar.url(:thumb) %>
but that doesnt work either
May be you are creating photo wrong.
Here you can see how the form looks: Nested form using paperclip
And also Post has_many :photos, so it must be somth. like
<% #posts.each do |f| %>
....
<% f.photos.each do |photo| %>
<%= image_tag photo.avatar.url(:thumb) %>
<% end %>
...
<% end %>
When I work with nested attributes I follow three steps. First, in the parent model you can use accepts_nested_attributes_for:
Class Post
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos
attr_accessible :photos_attributes
end
Second, you can incorporate a nested form for photos so you can set the attributes of photos for that particular post:
<%= form_for(#post) do |f| %>
<%= f.fields_for :photos do |p| %>
...rest of form here...
Third, you can create a photo through the new action in the post model:
Class UserController
def new
#user = User.new(photos: Photo.new)
end
end
This last step is important. If you don't do this, you would not see the photo fields in the user form otherwise. If you follow these steps you should be able to set all the attributes from both photos and users in the users form.
I think in your controller you should first define which is the post object you are associating to :
def new
#post = Post.find(params[:post_id]
#photo = #post.photos.build
....
end
The same is in the create action of the PhotosController .