Ruby On Rails how do I constrain my index between two dates - ruby-on-rails-4

I'm converting one of my apps from PHP to rails 4 and I'm stuck on making my index view default to a constraint on the date and also accept a start and end date from the params for the constrain.
The query in my PHP reads like so:
$query = " SELECT * FROM EVENTS WHERE EVENT_DATE >= '$start' AND EVENT_DATE <= '$end' ORDER BY EVENT_DATE ASC "
So that is probably similar to what active record needs to give me in the end.

Event.where('event_date >= ? and event_date <= ?', start_date, end_date).order('event_date ASC')
where start_date and end_date - are your dates, and Event - is your event model

You can put scope in your model, most probably in event.rb .
scope :between_dates , -> (start_date,end_date) { where("'EVENT_DATE' >= ? AND 'EVENT_DATE' <= ?", start_date,end_date).order("'EVENT_DATE' ASC") }
And then you can call something like this in your index controller
def index
#events = Event.between_dates(1.day.ago, 2.day.ago)
end
PS: the above method will generate the desire query.

Related

Rails Update More Effiecient

I need to update all my entries every 5 minutes. I am using Rails version 4.2.5 and Ruby version 2.3.0. My code below has worked fine with a small number of entries. I have about 800 entries now and it is taking up to 2 minutes to update. Is there a more efficient way?
#players = Entry.all
for player in #players
sort = 0
#player_selection = Selection.includes(:golfer).where("entry_id = ?", player.id).order('golfers.score asc').all
for selection in #player_selection
sort += 1
score_sort = Selection.where("id = ?", selection.id).first
score_sort.sort = sort
score_sort.save
player = Entry.where("id = ?", selection.entry_id).first
player.score = Selection.includes(:golfer).where("entry_id = ? and selections.sort < 6", selection.entry_id).sum('golfers.score')
player.save
end
end
Thank you.
Seems to me that you could offload some of your work to when records are created and/or updated (instead of aggregating them on a schedule).
e.g. something like:
# I assume your relationship is something like this:
class Golfer
belongs_to :entry
after_create :update_scores
after_update :update_scores
private
def update_scores
entry.update(score: entry.golphers.sum(:score))
end
end
This will reduce the workload when you run your sort update process.
Then your sort update process could be streamlined:
#entries = Entry.all
#entries.each do |entry|
sort = 0
#selections = Selection.includes(:golfer).where("entry_id = ?", player.id).order('golfers.score asc')
#selections.each do |selection|
sort += 1
selection.update(sort: sort)
end
end
by removing the extraneous data request, this will slightly improve the operation. However, your current operations are going to be linear at-best because you are running it as loop: (O)n + 1 runtime. You would likely have to drop into SQL to have a significantly faster computation:
# -> SQL; depends on DB a bit
UPDATE selections s
s.sort = ns.new_sort
FROM
(SELECT id, ROW_NUMBER() OVER (ORDER BY score ASC) AS new_sort
from selection) as nt
you could run a pure SQL command using Rails, as such:
# Be careful, this is dangerous
sql = "UPDATE ... your sql query here"
ActiveRecord::Base.connection.execute(sql)

How to display columns depending on the date selected [From and To] in rails?

|Jan_2016|Feb_2016|Mar_2016|Apr_2016|May_2016|June_2016|July_2016|Aug_2016|Sept_2016|Oct_2016|Nov_2016|Dec_2016|
"From" and "To" filter are there in which we have to select dates. Depending upon the values selected, we have to select columns dynamically which lies between selected date filters.
These are different columns. I have to display columns depending on the date selected in From and To datepicker in rails.
eg: Suppose "From:=>Jan_2016" and "To=>June_2016" then we have to dsplay all columns between these two dates[like => |Jan_2016|Feb_2016|Mar_2016|Apr_2016|May_2016|June_2016|].
Thanks.
Try this. It is not the best possible solution but it may work.
start_date = params[:to]
end_date = params[:from]
columns = Model.column_names
# For date filters
start_date_index = columns.index(start_date)
end_date_index = columns.index(end_date)
result = columns[start_date_index..end_date_index]
This is your solution
current_date = from.to_date
result = []
while ( current_date <= to.to_date )
result << current_date.strftime("%b_%Y")
current_date = current_date.next_month
end
result contains the columns you have to display

Sorting events to show this week, month etc

I have a list of events but I'm struggling to work out how to show specific date ranges in the index view.
I would like to list the events by showing events today, this week, this month etc.
I'm new to rails so I've tried to use this site and I've come up with the following which works for today's events.
#events_today = Event.find(:all, :conditions => ["date between ? and ?", Date.today, Date.tomorrow])
But I'm not sure how to set the page to automatically update and show only this weeks events and this month.
Your basic query should do something like this:
Event.where(date: date_range)
Now before calling this query you can set the date range variable. If you only want this week:
date_range = Date.today.beginning_of_week..Date.today
Event.where(date: date_range)
Now there are all sorts of things you can do. You can select a start and end date or a custom period using either a form or a dropdown select. In this case date_range is set based on your params. You could also always use one predefined period.
If you want to work with several date range periods it could be nice to have a last_week, last_month, etc. scope in your model (or concern). Or you could simply define date_range constants in your initializers.
As per my understanding, you want to show all the event of a week or month on click of tab 'Week' or 'Month' from view.
When you clicked on month or week for getting events, you send simply month or week in params(assuming params[:events_in] hold 'week' or 'month')
apply check on this attributes of params
def get_events_in_week_or_month
if params[:events_in] =='week'
start_date_of_time_period = Date.today.beginning_of_week
end_date_of_time_period = Date.today.end_of_week
else
start_date_of_time_period = Date.today.beginning_of_month
end_date_of_time_period = Date.today.end_of_month
end
#events in descending order
#events = Event.where("date between ? and ? ", start_date_of_time_period, end_date_of_time_period).order("created_at DESC")
#events in ascending order
#events = Event.where("date between ? and ? ", start_date_of_time_period, end_date_of_time_period)
end
for getting more methods of date class, you should run following command on rails console :
Date.public_methods

Django raw query filter by year and month

I need to write django raw query for filtering year and month. for that I have tried following code.
cursor = connection.cursor()
cursor.execute('SELECT SUM(work_time) AS sum FROM structure_tracking_details WHERE employee_id = %s AND tree_id=%s AND project_structure=%s AND year(date)=%s AND month(date)=%s GROUP BY project_structure ', [employee_id,tree_id,project_structure,select_year,select_month] )
sum1=str(cursor.fetchone())
but it tells no such function: year what's wrong with my code?
SQLite doesn't have a YEAR() function. If you want year, you can use something like this -
select strftime('%Y', datetime(datefield, 'unixepoch')) as year from table_name
So instead of writing year(date)=%s, you could write strftime('%Y', date) = %s. It should work. I haven't tried it.
Or leave all these headache and use Django's ORM. You should be using that at the first place.
Edit:
According to OP, this query worked -
cursor.execute("SELECT SUM(work_time) AS sum FROM structure_tracking_details WHERE employee_id = %s AND tree_id=%s AND project_structure=%s AND strftime('%%Y', date) = %s AND strftime('%%m', date) = %s GROUP BY project_structure ", employee_id, tree_id, project_structure, select_year, select_month])
The %Y needed to be escaped using %%Y.
Why don't you use the ORM?
If you have a model like this:
class Work(models.Model):
date_field = models.DateField()
# your other fields
You can do this query using the year and month lookups:
Work.objects.filter(date_field__year=2013,date_field__month=2)
Now, to add the rest of your stuff, which is the summing of work_time and group by:
from django.models import Sum
Work.objects.filter(date_field__year=2013,
date_field__month=2,
employee_id=1,
...).values('project_structure').aggregate(total=Sum('work_time'))

Doctrine 2 edit DQL in entity

I have several database tables with 2 primary keys, id and date. I do not update the records but instead insert a new record with the updated information. This new record has the same id and the date field is NOW(). I will use a product table to explain my question.
I want to be able to request the product details at a specific date. I therefore use the following subquery in DQL, which works fine:
WHERE p.date = (
SELECT MAX(pp.date)
FROM Entity\Product pp
WHERE pp.id = p.id
AND pp.date < :date
)
This product table has some referenced tables, like category. This category table has the same id and date primary key combination. I want to be able to request the product details and the category details at a specific date. I therefore expanded the DQL as shown above to the following, which also works fine:
JOIN p.category c
WHERE p.date = (
SELECT MAX(pp.date)
FROM Entity\Product pp
WHERE pp.id = p.id
AND pp.date < :date
)
AND c.date = (
SELECT MAX(cc.date)
FROM Entity\ProductCategory cc
WHERE cc.id = c.id
AND cc.date < :date
)
However, as you can see, if I have multiple referenced tables I will have to copy the same piece of DQL. I want to somehow add these subqueries to the entities so that every time an entity is called it adds this subquery.
I have thought of adding this in a __construct($date) or some kind of setUp($date) method, but I'm kind of stuck here. Also, would it help to add #Id to Entity\Product::date?
I hope someone can help me. I do not expect a complete solution, one step in a good direction would be very much appreciated.
I think I've found my solution. The trick was (first, to update to Doctrine 2.2 and) using a filter:
namespace Filter;
use Doctrine\ORM\Mapping\ClassMetaData,
Doctrine\ORM\Query\Filter\SQLFilter;
class VersionFilter extends SQLFilter {
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) {
$return = $targetTableAlias . '.date = (
SELECT MAX(sub.date)
FROM ' . $targetEntity->table['name'] . ' sub
WHERE sub.id = ' . $targetTableAlias . '.id
AND sub.date < ' . $this->getParameter('date') . '
)';
return $return;
}
}
Add the filter to the configuration:
$configuration->addFilter("version", Filter\VersionFilter");
And enable it in my repository:
$this->_em->getFilters()->enable("version")->setParameter('date', $date);