How would you go about producing reports by user selected date ranges in a rails app? What are the best date range pickers?
edit in response to patrick : I am looking for a bit of both widget and active record advice but what I am really curious about is how to restfully display a date ranged list based on user selected dates.
Are we asking an interface question here (i.e. you want a widget) or an ActiveRecord question?
Date Picking Widgets
1) Default Rails Solution: See date_select documentation here.
2) Use a plugin : Why write code? I personally like the CalendarDateSelect plugin, using a pair of the suckers when I need a range.
3) Adapt a Javascript widget to Rails: It is almost trivial to integrate something like the Yahoo UI library (YUI) Calendar, which is all Javascript, to Rails. From the perspective of Rails its just another way to populate the params[:start_date] and params[:end_date]. YUI Calendar has native support for ranges.
Getting the data from the Widgets
1) Default Rails Solution See date_select documentation here.
#an application helper method you'll find helpful
#credit to http://blog.zerosum.org/2007/5/9/deconstructing-date_select
# Reconstruct a date object from date_select helper form params
def build_date_from_params(field_name, params)
Date.new(params["#{field_name.to_s}(1i)"].to_i,
params["#{field_name.to_s}(2i)"].to_i,
params["#{field_name.to_s}(3i)"].to_i)
end
#goes into view
<%= date_select "report", "start_date", ... %>
<%= date_select "report", "end_date", ... %>
#goes into controller -- add your own error handling/defaults, please!
report_start_date = build_date_from_params("start_date", params[:report])
report_end_date = build_date_from_params("end_date", params[:report])
2) CalendarDateSelect: Rather similar to the above, just with sexier visible UI.
3) Adapt a Javascript widget: Typically this means that some form element will have the date input as a string. Great news for you, since Date.parse is some serious magic. The params[:some_form_element_name] will be initialized by Rails for you.
#goes in controller. Please handle errors yourself -- Javascript != trusted input.
report_start_date = Date.parse(params[:report_start_date])
Writing the call to ActiveRecord
Easy as pie.
#initialize start_date and end_date up here, by pulling from params probably
#models = SomeModel.find(:all, :conditions => ['date >= ? and date <= ?',
start_date, end_date])
#do something with models
It's not an unRESTful practice to have URL parameters control the range of selected records. In your index action, you can do what Patrick suggested and have this:
#initialize start_date and end_date up here, by pulling from params probably
#models = SomeModel.find(:all, :conditions => ['date >= ? and date <= ?', params[:start_date], params[:end_date]])
Then in your index view, create a form that tacks on ?start_date=2008-01-01&end_date=2008-12-31 to the URL. Remember that it's user-supplied input, so be careful with it. If you put it back on the screen in your index action, be sure to do it like this:
Showing records starting on
<%= h start_date %>
and ending on
<%= h end_date %>
Related
When a user creates a vacancy I want them to be able to save either 1 range of dates or multiple separate dates.
So I have 2 models, Vacancy and Vacancyschedule.
Vacancyschedule includes vacancy_id start_date end_date start_hour end_hour (to save a range) and when it is multiple seperate dates, I just want to leave the end_date empty and have multiple entries and combine them through my vacancy_id.
This is my code in my view:
... other code to ask for vacancy params, nothing special, nothing broken ...
#Code to create entry in vacancyschedule
<%= t.simple_fields_for :vacancyschedule do |p| %>
<%= p.input :start_date, :as => :date_picker, :label => false%>
<%= p.input :start_hour, as: :time, default: Time.parse('09:00')%>
<%= p.input :end_hour, as: :time, default: Time.parse('17:00')%>
<% end %>
And then I have some javascript that adds another exact copy one of those blocks when a user wants to add a second seperate date.
Now for my question:
The format in which they are passed is very strange. As you can see I ask for :start_date, :start_hour and :end hour and this is what I get:
{"name"=>"", "street"=>"", "description"=>"", "skill_id"=>"",
"jobtype_id"=>"", "wage"=>"", "vacancyschedule"=>
{"start_date"=>"27/10/15", "end_date"=>"", "start_hour"=>"",
"end_hour"=>"", "start_hour(1i)"=>"2015", "start_hour(2i)"=>"10",
"start_hour(3i)"=>"26", "start_hour(4i)"=>"21",
"start_hour(5i)"=>"00", "end_hour(1i)"=>"2015", "end_hour(2i)"=>"10",
"end_hour(3i)"=>"26", "end_hour(4i)"=>"17", "end_hour(5i)"=>"00"},
"vacancyscheduele"=>{"start_date"=>"", "start_hour(1i)"=>"2015",
"start_hour(2i)"=>"10", "start_hour(3i)"=>"26", "start_hour(4i)"=>"09",
"start_hour(5i)"=>"00", "end_hour(1i)"=>"2015", "end_hour(2i)"=>"10",
"end_hour(3i)"=>"26", "end_hour(4i)"=>"17", "end_hour(5i)"=>"00"},
"tag_list"=>""}, "radio"=>"on", "commit"=>"Create Vacancy",
"controller"=>"vacancies", "action"=>"create", "employer_id"=>"2"}
From what I can see is that they are passed in very different variables and incomplete (not all dates are passed).
Does anyone have any experience with this issue? How would I either grab these elements or how do I prevent them from being pushed in that format?
Eeeehhh, I hate nested forms. I always go back to the basics when I have to deal with them. Checkout these fine railscasts. The second one I think is better aimed at your problem but the first one helps understand it:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
At the end of the day, you need to know what your html is generating and make sure it is what Rails is expecting in the backend. Also, you must account for the nested objects at load and save time. Your HTML as it stands, is not generating parseable objects as far as Rails is concerned. On the other hand, it is hard to deal with the crap date/time picker for Rails. I usually like to put in something that generates a better date picker. One that generates one string that is easily maps to a database field. If you are using bootstrap, I'd use the bootstrap datepicker gem.
Rails ~ 4.2.1
Mongoid ~ 4.0.2
in _form.html.erb, the code looks like this:
<%= form_for #workout %>
<%= f.label :date%>
<%= f.datetime_select :date>
<%= f.submit %>
<% end %>
in Workout.rb, the code looks like this:
class Workout
include Mongoid::Document
field :date, type: DateTime
end
I naively thought The View could send {"workou[date]" => "2015/06/20 10:10"} to the Controller, but actually, it sent {"workout[date(1i)]" => "2015", workout[date(2i)] => "06", ... workout[date(5i)] => "10"}. In the end, in Mongo workout collection, it stored the time separately.
I want Mongo DB to store them in one field, type as DateTime. How can I achieve that?
You ask for Datetime, but maybe my answer (using Date type) can lead you the way too. Let's see.
This answer suggests the Best way to store date/time in mongodb. That is if you can you should choose native JavaScript Date objects.
The way I solve my issue (with Date object) was as follows.
I use the Date field type in my models. E.g. the Event model has two date types, from_date and end_date.
In the controller (e.g. new method) you can use the Date object as usual, no special treatment in my case. I guess for you it is the same. E.g. Date.current or Date.current+3.days.
Note the create method does not specifically manipulate Date objects. The parameters from the web view form are taken as is.
In the view I use the date_field helper. It is an input field of type date. Note that currently Google Chrome supports the date field type, so you will see a date picker pop up. Other browsers don't support the field yet, so it is a simple input field for them. I use jQuery Datepicker in case the browser does not support the input date type field, e.g.
$(document).ready(function(){
...
if ( $('[type="date"]').prop('type') !== 'date' ) {
$('input[type="date"]').datepicker({dateFormat: "yy-mm-dd"});
}
...
});
So in your case maybe you could do something analogue to that
solution. Probably there is no datetime_field helper method, but a
simple input field could do and you use JS to ensure you are saving a
native JS Date/Datetime object for the corresponding field.
in my Rails 3.1, ruby 1.9.2 application, I've an Object 'Post' that has several fields such as id,created_at,updated_at,name,description.... In my view I want show post.created_at field filtered by date: I explain better:
In my view I'd want something such as:
but html must render something such as: 2011-30-06 and not 2011-30-06 11:04 am
in other words I want display only date and not hour, how can I do?
You should use strftime to format correctly the date (here's the documentation)
It should look like this <%= post.created_at.strftime("%Y-%M-%d) %>
I'd suggest to create method display_date in application_helper.rb, don't forget about DRY!
def display_date(input_date)
input_date.strftime("%Y-%M-%d")
end
So I took some php code and turned it into a calendar with a helper to make a simple calendar.
I got my data from inside the helper:
def calendar_maker
a = Time.now
b = a.month
d = a.year
h = Time.gm(d,b,1) #first day of month
Now I want to try and do it with parameters within my method
#from the helper file
def calendar_maker(year, month)
a = Time.now
b = month
c = year
h = Time.gm(d,b,1) #first day of month
#from my html.erb file
<%= #month %> and <%= #year %>
<%= params["month"] %><br />
<%= params["action"] %><br />
<%= params["year"] %><br />
<%= calendar_maker( #year, #month) %>
#from controller file
def calendar
#month = params[:month]
#year = params[:year]
end
Anyways mistakes were made and not finding documentation anywhere or not looking in the right place. How do I get this to work with my params hash using instance variables #month and #year from the controller and my local parameters in my calendar_maker method year and month. Do I just grab the value from the params hash and assign it directly to the instance variable in my helper or controller? Thanks for the help.
You have this tagged as Rails and there's erb, so I'll assume that's true. You should look at all the gee-whizzy date helpers Rails has to offer. You just don't have to do this stuff.
Specifically, beginning_of_month completely replaces your calendar_maker stuff, if I understand it correctly. So you could do Date.today.beginning_of_month to replace your helper.
If you have a controller action called #calendar and a view file called html.erb, your view file will not, by default, be rendered as it doesn't follow the correct naming convention. You'd want to name the erb file calendar.html.erb. You might have done this and truncated the name in your code example.
If you could be more specific about what exactly is going wrong, you will get more helpful feedback. What errors are you seeing? What did you get as opposed to what you expected to get. That kind of thing.
Oh, and Rails has date_select and datetime_select if you are just looking for a quick way to get that information into a form.
I have followed Ryan Bates tutorial on nested models. Several of my nested models have dates associated with them. In my migrations, they are actually the type "Date."
Some things I have tried and problems I've run into
date_select - can handle the form object prefix, but not nested models attributes
select_year - doesn't work with form object
a regular select populated with the year by using (Time.now.year - 100)..(Time.now.year) and overriding the attr accessor start_date and end_date to take the value in the select to form a date and passing that back. works on create only, not on update
changing the data type of the field to string and using a regular select populated with the year by using using (Time.now.year - 100)..(Time.now.year) works, but on edit, it won't repopulate the select with the current information
Any ideas or hints would be helpful.
Edit: before_save seems to be more promising but for some reason, the value is nil coming into before save but is visible in the log dump.
Edit 2: Interestingly, this only seems to be a problem on 'update', not on 'create'.
This is the solution:
<% new_or_existing = task.new_record? ? 'new' : 'existing' %>
<% prefix = "project[#{new_or_existing}_task_attributes][]" %>
<% fields_for prefix, task do |t| -%>
<%= t.date_select(:start_date, :index => task.id || nil) %>
<% end -%>
Here's the explanation of why it works:
http://agilerails.wordpress.com/2009/03/11/date_select-time_select-doesnt-work-with-auto_prefix-object/
I'd seriously hope that this works for date_select as well:
http://jeffperrin.com/2009/06/04/rails-nested-forms-and-collection_select/
Maybe this would work with the formtastic gem...