Loop through two object arrays, sort by date created - ruby-on-rails

I'm trying to sort out how to loop through two object arrays and display them in mixed order in a view – by the date they were created.
Here's my current controller code, that only displays Posts based on the category you're in, or, based on a search query:
def browse
#user = current_user
if params[:category]
#category = Category.find(params[:category])
#posts = #category.posts.page(params[:page])
else
#posts = Post.search(params)
end
end
In the view, I just loop through and output these like so:
- if #posts
- #posts.each do |post|
= post.name
= post.content
What I'd like to do, is instead of referencing posts via the instance variable #posts... I'd like to create a new variable (ie: #everything) – that pulls objects from the Post class and the Comment class, pops them into the same array, and allows me to loop through and output each respectively in my view, like this:
Ideal controller:
def browse
#user = current_user
if params[:category]
#category = Category.find(params[:category])
#everything = #category.everything(params[:page]) # ... combination of comments and posts
else
#everything = Everything.search(params)
end
end
Ideal view:
- if #everything
- #everything.each do |e|
- if e.type == 'post'
= e.name
= e.content
- else
= e.comment
Any help/guidance is appreciated. I'm just not sure how to approach this.

You would do this type of thing (to get you started)
def browse
#user = current_user
#everything = #category.posts | #category.comments
end
In the view
%ul= render #everything
Make sure there is a views/comments/_comment.html.haml and a views/posts/_post.html.haml files.
Or you could render a specific partial and handle any differences in there
%ul= render :partial => shared/everything_item, :collection => #everthing

Related

Render a partial that uses helper methods to determine view

What Currently Works:
In my BookingsController#Index method, I have this
def index
#user = current_user
if #user.user_type == 'host'
#bookings = Booking.where(host_id:#user.id, status: "#{params[:status]}")
else #user.user_type == 'cleaner'
#bookings = Booking.where(cleaner_id:#user.id, status: "#{params[:status]}")
end
end
This sets the current user and determines which #bookings to display depending on the user_id and params.
In the views, in my index.html.erb file, I render bookings <%= render #bookings %> which i defined in the booking#index. I have a _booking.html.erb partial that gets rendered... Inside the _booking.html.erb partial, I am able to successfully return booking details , like this for instance,
<div id='booking-time'><b>Unit Name:</b> <%= booking.unit.name %></div>
will return the unit name. it recognizes the local variable booking and the fields that belong to it.
I'd Like to Refactor:
I want to refactor this and render a partial <%= render 'bookings/booking' %> in my index.html.erb file. This partial will render different helper methods that each route to different partials.
Currently my _booking.html.erb file has a bunch of conditional logic that is better suited for a helper... I've tried a bunch of different ways to accomplish this to no avail, usually due to undefined variables..what's an elegant way to accomplish this?
What I've Tried:
Here's a method from my bookings_helper.rb` file:
def incoming_to_cleaner_partial_path(bookings)
return unless booking.status=='pending' && current_user.user_type =='cleaner' && booking.requested_by_id != current_user.id
'bookings/booking_requests/incoming_to_cleaner'
end
I added logic to these methods to determine which partials to render.
in my modified _booking.html.erb file, I call these methods, I pass them a #bookings instance variable param.
<%= render incoming_to_cleaner_partial_path(#bookings) %>
I've also tried this without params.. Neither work..
lastly, I've tried calling a method determine_bookings_to_show inside the helper methods. This method contains the same logic from the controller...
def incoming_to_cleaner_partial_path
determine_bookings_to_show
return unless booking.status=='pending' && current_user.user_type =='cleaner' && booking.requested_by_id != current_user.id
'bookings/booking_requests/incoming_to_cleaner'
end
private
def determine_bookings_to_show
#user = current_user
if #user.user_type == 'host'
#bookings = Booking.where(host_id:#user.id, status: "#{params[:status]}")
else #user.user_type == 'cleaner'
#bookings = Booking.where(cleaner_id:#user.id, status: "#{params[:status]}")
end
end
My main issue is i'm having scope troubles with these partials...
.. in my index [I want to] render different partials [depending on attributes of the booking] ..
I have used render(locals:) for this in the past.
# index.html.erb
#bookings.each do |b|
render_booking(b)
end
# bookings_helper.rb
def render_booking(booking)
if booking.status == 'pending'
render partial: 'path/to/bookings/_pending', locals: { booking: booking }
elsif booking.foobar?
render partial: 'path/to/bookings/_foobar', locals: { booking: booking }
else
# etc.
end
end
Conditionals like this can get complicated, but until then, I think this is an appropriate, practical use of a helper method.
# bookings/_pending.html.erb
<h1>Pending Booking <%= booking.id %></h1>
You will likely need to pass other locals:. I'd avoid using any instance variables in your partials.

Map name of model object to a pg_search query param in Rails 5.1

I have an album model, that has one 'cover_image' and has_many 'images'. I also have a product model. I am using pg_search to filter my products.
Independently, they both work flawlessly. What I would like to do is show an albums cover_image based on the pg_search filter param.
For example: If I had a filter param called "limestone", I would create an album called "limestone" and when a user filters the page by limestone, they would get the product results along with the matching cover_image.
product_controller - this works for filtering
def index
#products = if params[:query]
Product.search_for(params[:query])
else
Product.order(:name)
end
end
product_controller - this breaks the page
I tried this in an attempt to keep it simple and filter the image in the model
def index
#products = if params[:query]
Product.search_for(params[:query])
*#albums = Album.where(name:(params[:query]))*
else
Product.order(:name)
end
end
products/index.html.erb Then I would just call the album as normal.
...
<% #albums.each do |a| %>
<%= image_tag("#{a.cover_image_url(:original)}") %>
<% end %>
...
The problem is that you're assigning #albums to #products. This is in effect what you're doing:
#products = #albums = Album.where(name: (params[:query]))
because the if statement is returning #albums. So this should work (assuming that the rest of your logic is correct):
def index
#products = if params[:query]
#albums = Album.where(name: params[:query])
Product.search_for(params[:query])
else
Product.order(:name)
end
end
However, I would not assign #albums where you are doing so right now. I think this is clearer thus slightly better:
def index
if params[:query]
#products = Product.search_for(params[:query])
#albums = Album.where(name: params[:query])
else
#products = Product.order(:name)
#albums = []
end
end

Rails:Is it possible to have 2 different each do loops on the same view?

Is it possible to have 2 .each do on the same view. With them doing different searches?
For example if I want to display all posts made by one specific user. I would have the following action in my users controller:
def show
#user = User.find(params[:id])
#posts = #user.posts
end
Then in the view I would have:
- #posts.each do |post|
=post.title
Then If I wanted to display posts by other users on the same view. Using the above wont work as its only searching for the specific users posts.
Would I then create a new action?
Something like the following:
def showAll
#user = User.find(params[:id])
#posts = Post.where(:attribute => value).order("created_at DESC")
end
Then back in the view page I would have another each.do with this one being the showAll action like:
- #posts.each do |post|
=post.title
How would I achieve this? Is this the correct way to use actions?
Yes, you can do that in the same action itself
def show
#posts = current_user.posts
#other_posts = Post.where(:attribute => value).order("created_at DESC")
# OR
# #other_posts = Post.where.not(id: #posts).order("created_at DESC")
end
And then you can loop over them in view
%h2 Your posts
- #posts.each do |post|
= post.title
%h2 Posts from other users
- #other_posts.each do |post|
= post.title

Rails Two Views With One Controller#Action

I created a rails association "user has many follows" currently have lists of user's followers and followings. I want to have 2 links onusers#show to display lists of followers and followings. I know I can render two different views in my follows#index using if else statement but I'm not sure how to go about it. My initial thought was to have rails check which link was clicked (either 'Followers' or 'Followings') but I couldn't find an exact answer. I also thought of creating two different tables (Followers, Followings) but adding 2 same values for 1 action seemed redundant and waste of space.
Here is my FollowsController:
class FollowsController < ApplicationController
def index
#follows = Follow.all
render :index
end
def create
#follow = Follow.create(follow_params)
redirect_to user_url(#follow.user_id)
end
def destroy
#follow = Follow.find(params[:id])
#follower_id = #follow.user_id
#follow.destroy!
redirect_to user_url(#follower_id)
end
private
def follow_params
params.require(:follow).permit(:follower_id, :user_id)
end
end
What would be the best approach?
Example:
def index
#follows = Follow.all
if #follows.present?
render 'show_with_followers'
else
render 'show_without_followings'
end
end
views
app/views/follows/_show_with_followers.html.erb
app/views/follows/_show_without_followings.html.erb
Here is an answer I found so far. I will be using in my view
<%= link_to 'Followers', follows_path(:follows => 'followers') %>
<%= link_to 'Followings', follows_path(:follows => 'followings') %>
and use
def index
if params["follows"] == 'followers'
#render followers
else
#render followings
end
end
end

Rendering a rails partial inside of another partial

I have a page listing many products, at taxons#show. Inside of taxons#show I'm rendering the partial _products.html.erb to display the products, images, variants, etc. By default, when you click an individual product on taxons#show rails redirects you to the products#show page where the partial _cart_form.html.erb is rendered which displays add to cart options.
However, I'm trying to render _cart_form.html.erb inside a lightbox in _products.html.erb, which is inside of taxons#show. My problem is that _products.html.erb is using
<% products.each do |product| %>
to display each individual product. And _cart_form.html.erb is using #product to display all of its product info. If I keep it this way I get a NoMethod error for nilClass because #product isn't defined.
Then I tried:
<% #product = product %>
<%= render 'spree/shared/cart_form' %>
But because this is above the code that outputs all of the products on taxons#show it changes every product inside _product.html.erb to the same product, the first one listed.
How can I render _cart_form.html.erb inside of a lightbox for each individual product?
Here's taxons_controller.rb:
def show
#taxon = Taxon.find_by_permalink(params[:id])
return unless #taxon
#taxon_id = params[:id].split('/').first
if #taxon_id
instance_variable_set "#enable_#{#taxon_id}", true #big lettered taxonomy heading
end
#product_type = params[:id].split('/').last
#featured = #taxon_id + '/' + #product_type #featured image
#searcher = Spree::Config.searcher_class.new(params.merge(:taxon => #taxon.id))
#searcher.current_user = try_spree_current_user
#searcher.current_currency = current_currency
#products = #searcher.retrieve_products
#related_products = #taxon.products.offset(rand(Spree::Product.count - 7)).limit(7)
respond_with(#taxon)
And products_controller.rb:
def show
return unless #product
#variants = #product.variants_including_master.active(current_currency).includes([:option_values, :images])
#product_properties = #product.product_properties.includes(:property)
referer = request.env['HTTP_REFERER']
if referer
begin
referer_path = URI.parse(request.env['HTTP_REFERER']).path
# Fix for #2249
rescue URI::InvalidURIError
# Do nothing
else
if referer_path && referer_path.match(/\/t\/(.*)/)
#taxon = Taxon.find_by_permalink($1)
end
end
end
respond_with(#product)
end

Resources