how to group_by day in rails - ruby-on-rails

Hello I'm trying to make grouping news by date. I can't understand what is the problem?
feed_entries_controller.rb
def index
#feed_entries = FeedEntry.page(params[:page]).per_page(12).where('published_at < ?', DateTime.now)
#feed_entries_by_day = #feed_entries.group_by { |t| t.published_at.beginning_of_day }
end
index.html.erb
<% #feed_entries_by_day.each do |day, feed_entries| %>
<h3><%= h day.strftime("%d %B %Y") %></h3>
<%= render #feed_entries%>
<% end %>

Without seeing the data, I suspect our problem is the published_at column also contains time and we're just interested in the date part for the purposes of querying and grouping, and we need to reference the grouped data in the view..
If that's the case, we can amend our .where() clause like so:
feed_entries_controller.rb
def index
feed_entries = FeedEntry
.page(params[:page])
.per_page(12)
.where('published_at::date <= ?', Date.current)
#feed_entries_by_day = feed_entries.group_by { |t| t.published_at.to_date }
end
And in our view, we need to pick a different name to iterate through our grouped feed_entries (I've chosen entry)
index.html.erb
<% #feed_entries_by_day.each do |day, entry| %>
<h3><%= h day.strftime("%d %B %Y") %></h3>
<%= render entry%>
<% end %>

Related

Narrowing search with ransack

I've got workers, workers has many posts. I want to be able to search for a worker, displaying all his posts, then narrow down to the date the posts where made. I can search by name of the worker but when I try to search for date aswell it just displays all posts for that worker (if the date exists in one post).
what I'm trying to run with:
controller:
#q = Worker.ransack(params[:q])
#workers = #q.result.order(name: :asc).includes(:posts).uniq
view:
<%= search_form_for #q do |f| %>
<%= f.label :name_cont %>
<%= f.search_field :name_cont %>
<%= f.label :posts_date_start %>
<%= f.search_field :posts_date_start %>
<%= f.submit %>
<% end %>
<% #workers.each do |worker| %>
<% worker.posts.group_by { |t| t.date.to_time.beginning_of_month }.each do |month, posts| %>
<some table header logic>
<% posts.each do |post| %>
<table content>
Unless you created a custom predicate of start, that will not work.
From your group_by statement I can see that your posts has a date field. If you wanted posts only for the date specified you would use the eq predicate
<%= f.search_field :posts_date_eq %>
If you need to massage your user input, I would look into making a custom predicate you can look at how to do that here -> creating custom predicates
EDIT
To test parsing your date field string into a date put
begin
params[:q][:posts_date_eq] = Date.parse(params[:q][:posts_date_eq])
rescue
# no param present
end
before your search object
#q = Worker.ransack(params[:q])
I solved it like this
instead of
<% worker.posts.group_by { |t| t.date.to_time.beginning_of_month }.each do |month, posts| %>
I did
<% Post.search_post(params[:search_post]).search_post_present(params[:search_post_present]).where(worker_id: worker.id).order(date: :asc).group_by { |t| t.date.to_time.beginning_of_month }.each do |month, posts| %>
that pointed to a search hepler in post.rb
def self.search_post(search_post)
if search_post
where('date LIKE ?', "%#{search_post}%")
else
all
end
end
I then overlapped the forms for both ransack and this search, so both are run with the same submit button, and that worked just fine.

Using search function in rails to retrieve a result and display it first in the index page

I am trying to implement search functionality in my rails app where I search and display a particular search result first on my index.html.erb view. At the moment I have a search function working and it returns the particular item on its own on the index page.
Ideally I would like to have this item displayed first and then all the other items to display below.
My code is as follows:
brand.rb
def self.search(query)
where("author like ?", "%#{query}%")
end
brand_controller.rb
def index
if params[:search]
#brand = Brand.search(params[:search]).order("created_at DESC")
else
#brand = Brand.all.order(':date')
end
end
I know the where method returns the value as an array so I could probably use array.first to output this result first but is there an easier way to output my desired view. Thanks!
So turned out to be a pretty simple solution, I blame mondays.
All I had to do was create another variable for my search and iterate that result first, then iterate through the rest of the items.
in my controller
def index
#brand = Brand.order('created_at DESC')
if params[:search]
#brand = Brand.search(params[:search]).order("author DESC")
#other = Brand.search_all(params[:search]).order("author DESC")
else
#brand = Brand.all.order('author DESC')
end
end
In my model
def self.search(query)
where("author like ?", "%#{query}%")
end
def self.search_all(query)
where("author not like ?", "%#{query}%")
end
and finally in my view
<% if #brand.any? %>
<% #brand.in_groups_of(2) do |group| %>
<% group.each do |brand| %>
<% if brand %>
<h4> <%= brand.author %></h4>
<a href="<%=brand_path(brand)%>">
<%=image_tag brand.brand_logo, class: 'img-rounded', :"data-uid" => brand.uid %> </a>
<% end %>
<% end %>
<% end %>
<% end %>
<% if #other %>
<% #other.in_groups_of(2) do |group| %>
<% group.each do |other| %>
<% if other %>
<h4> <%= other.author%></h4>
<a href="<%=brand_path(other)%>">
<%=image_tag other.brand_logo %> </a>
<% end %>
<% end %>
<% end %>
<% end %>

grouping children by parent attribute

Here's what I am trying to achieve:
Group_x.name
member1.name -- member1.join_date -- etc
member2.name -- member2.join_date -- etc
...
Group_y.name
member1.name -- member1.join_date -- etc
member2.name -- member2.join_date -- etc
...
What I'm going for is really very similar to this although the implementation there doesn't work for me.
I've gotten this far in my controller:
def index
# https://stackoverflow.com/a/17835000/2128691
#user_group_ids = current_user.student_groups.map(&:id)
#students = Student.where('student_group_id IN (?)', #user_group_ids)
# https://stackoverflow.com/a/10083791/2128691
#students_by_group = #students.uniq {|s| s.student_group_id}
#title = "All students"
end
and calling the following in my view -
<% #students_by_group.all.each do |x| %>
<p>
<%= "#{x}" %>
</p>
<% end %>
gives me a list of all student objects. if i call <%= "#{x.name}" %> or <%= "#{x.created_at}" %>, etc, I get the correct information, and everything is great.
But now that I have all this information, how can I put the group.name (in my code it would be x.student_group.name) as a header for all of the students for which that group_name is true?
I think you need to use group_by on #students_by_group like this:
#students_by_group = #students_by_group.group_by { |s| s.student_group }
This would return a hash with the keys being the student group objects and the values being the students that belongs to this group, then you can do this in your view:
<% #students_by_group.each do |group, students| %>
<h3><%= group.name %></h3>
<% students.each do |x| %>
<p>
<%= "#{x}" %>
</p>
<% end %>
<% end %>
As an additional note, the group_by would fire a query for each student, so you may want to eagerly load the student group for each student like this for some performance gain:
#students = Student.where('student_group_id IN (?)', #user_group_ids).includes(:student_group)

Rails 3.1 - Events Listings - How to handle events that span many dates?

I'm building an events listing site. Currently each event is entered for a specific date and displayed in order......simple! However, I need to consider how to handle events such as festivals and plays that span more than one date. Entering the event over and over again for each date clearly isn't the best option. I've thought I could have a start date and end date, but i'm not sure how I would then make the event show in my index for the dates in between start/end. This is probably really simple, but I just thought i'd seek some guidance for those with more experience before I potentially set off down the wrong path with this.
The event schema at the moment:
create_table "events", :force => true do |t|
t.date "event_date"
t.string "headline"
t.text "info"
t.integer "event_type_id"
t.integer "venue_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "event_image_file_name"
t.string "event_image_content_type"
t.integer "event_image_file_size"
t.datetime "event_image_updated_at"
t.boolean "free"
end
And my Event Controller index does:
#events = Event.paginate(:page => params[:page], :per_page => 12).find(:all, :conditions => ['event_date >= ?', Date.today], :order => "event_date")
EDIT:
I should have pointed out that i'm listing the events with a date header generated by the following line in my Event Controllers Index method:
#events_dates = #events.group_by { |e| e.event_date }
The the view is something along the lines of:
<% #events_dates.sort.each do |event_dates, events| %>
<div class="well">
<h3>
<% if event_dates == Date.today %>
Today
<% elsif event_dates == Date.today + 1 %>
Tomorrow
<% else %>
<%= event_dates.to_date.to_formatted_s(:my_format) %>
<% end %>
</h3>
</div>
<%= render events %>
<% end %>
The events partial then has the event headline, info etc.
So, I think what I need to do is alter the way I loop through my date headers. Instead of grouping event dates from the db and then looping those, I almost need to loop through calendar days and see if events occur on those dates based on event_start_date and event_end_date. Any ideas how to approach that?
If you have a start and end date, using the conditions hash:
:conditions => ["event_start_date <= ? AND event_end_date >= ?", Date.today, Date.today]
Or arel:
.where("event_start_date <= ? AND event_end_date >= ?", Date.today, Date.today)
Edit:
Okay, so you want to iterate over a date range, and then display any events for that day. To iterate over a date range you'd use ruby's Date.upto() function, and for each date, you could then just iterate over the events, and only display events relevant for the current date.
The following code is assuming you've set up the #start_date and #end_date in the controller.
<% #start_date.upto(#end_date) do |date| %>
<div class="well">
<h3>
<% if date == Date.today %>
Today
<% elsif date == Date.today + 1 %>
Tomorrow
<% else %>
<%= date.to_formatted_s(:my_format) %>
<% end %>
</h3>
</div>
<%= render #events.select{|event| event.start_date < date && event.end_date > date} %>
<% end %>
There's a bit too much logic going on in the view here though, and you might have to do a little rejigging to get it to work, but it should get you on the right path.
I don't think you need to group by.
#events = Event.where('start_date >= ? AND end_date >= ?', Date.today.beginning_of_day], Date.today.beginning_of_day]).order(:start_date)
In your view do something like:
Today
<% for event in #events %>
<% if event.start_date == Date.today %>
<%= render "events/event" %>
<% end %>
<% end
Tomorrow
<% for event in #events %>
<% if event.start_date == Date.tomorrow %>
<%= render "events/event" %>
<% end %>
<% end %>
Is that what your trying to achieve?
You'll need to clean it up a bit, perhaps using a for event in #events.where date is today, but you get the idea

Rails: Multiple models records list

How can I show recent added #post and #photos in one list? For example:
post - LAlala (10.10.2011)
photos - [] [] [] [] (1.1.2011)
post - Bbbdsfbs (2.12.2010)
post - Lasdasdf2 (2.10.2009)
#posts = Post.limit(20).order('created_at desc')
#photos = Photo.limit(20).order('created_at desc')
#recent_items = (#posts + #photos).sort_by(&:created_at)
<% #recent_items.each do |item| %>
<% if item.class == "Photo" %>
<%= image_tag item.url %>
<% else %>
<%= item.title %>
<% end %>
<% end %>
Alternatively, use group_by to do it like this:
#recent_items = (#posts + #photos).group_by(&:created_at)
<% #recent_items.each do |date, items| %>
Date: <%= date %>
<% items.each do |item| %>
Show information here.
<% end %>
<% end >
I would move the view logic into a helper if I were you for DRYer code.
It is much better to do this is the database.
I just say this: polymorphism + database views.
Create a database view which contains the columns you need from both Post and Photo, including the column "type" containing a the name of the model (you need it for the polymorphism). Call this view for example "list_items". Then create a model called "ListItem". Then you can use this model like any other, paginate it and whatever you need to do.
ListItem.order("created_at > ?", Date.yesterday).page(params[:page])
And don't forget to configure the polymorphic association
However, all this is much easier to accomplish with the listable gem. Check it out!

Resources