Creating a date range picker using two select boxes in Rails - ruby-on-rails

I'd like to setup a model that would allow a date range depicting a timeframe of activity-inactivity. So for example you have an employee model and would be able to set his/her duration of employment from a start date to an end date. Essentially there would be two select boxes that would allow you to do this. If the employee is still employed there would be an option in the second box labeled "current".
I've looked around for an existing answer to this problem and it seems most direct you towards using either date_select or select_year to create a range within one select box. I'm looking to do something of the sort using two select boxes (start / end || current) and saving the two values to the database. Now for the second select box I wanted to have it default to the current year and be called "Current", indicating there is no end date yet.
Looking through the Rails API there's an option for a prompt but I'm not exactly sure how to have that prompt represent a physical value and reside at the top of the list. For something as simple as this I was leaning towards not using an extensive jQuery datepicker plugin to reduce the unnecessary overhead. I'm open to using SimpleForm but haven't found a way to do this through that gem.
What I have now:
<% form_for #product do |f| %>
<%= f.label :employed %>
<%= select_year(Date.today, start_year: 2000, end_year: 2012) %>
<%= select_year(Date.today, :start_year => Date.today.year, :end_year => 8.years.from_now.year) %>
<% end %>
I'm wondering if creating two attributes to the employee model specifying these date (stardate + enddate) would work or could you possibly do this in one fell swoop (I'm assuming the latter would be cleaner)?

I would consider creating a separate table to store these values, call it EmploymentPeriod. An Employee then has_many EmploymentPeriods, which could be useful to keep track of... (maybe an employee is a student, and works one summer, and then returns the following, for example).
EmploymentPeriod could keep track of things like start_date, end_date, and even something like salary, for that particular period (maybe the student gets a raise the following summer...).
To recap:
Employee has_many :employment_periods
EmploymentPeriod belongs_to :employee # e.g. it has an employee_id foreign key
This is how I would tackle it! Good luck.

Related

How do I create a drop down in a Rails form where the user can change the default value?

I'd like to have a drop down in my Rails form where users can select an area of a city, e.g. "Marchmont", "New Town", "Baberton" etc, when adding an order. I'd like that once they have made a selection, this will then be the default selection for the following times they use the form to add an order (so that they don't have to keep selecting it) but also that they can change their selection at any time. Hope that makes sense. I'm using the Simple Form gem. Thanks in advance! :)
#Steve
I will make a couple of assumptions.
1.) you know how to create forms within the rails templating engine.
2.) you understand how to create a dropdown menu using the Simple Form gem
So you have a couple of options based on what you actually want to accomplish. Based on what you are briefly describing, it sounds like you have some kind of an e-commerce/checkout situation that you want auto-completion to make it easier for a user.
there are a couple of approaches to storing this data.
Saving the user Data.
1.) Save it right on the user model under district_of_last_order
2.) Save it right on the order model that a user has_many orders. Then you can pull the first order's city district and select that
Personally I would lean on #2 as you probably want to be able to tightly couple the order with the user and saving that information twice is redundant since you can always do something like current_user.orders.first.district or whatever,
in your ERB where you build the form you can then do something along these lines:
<%= simple_form_for(#order) do |f| %>
... other input fields
<% if current_user.orders.first %>
<%= f.input as: :select selected: current_user.orders.first.district %>
<% else %>
<%= ... your regular dropdown menu here without the default %>
<% end %>
... rest of your form
If you have the option of using gems, I have had good results with select2-rails.

Create multiple entries in model through nested form via simple_form

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.

How do I add an attribute to an instance variable in rails 4?

Using Rails 4, in a controller I would like to add an attribute to an instance variable.
Sorry for the poor example, I'm trying to keep it simple.
E.g. In a controller, I create a new instance variable by looking up some users named John. Now, in my controller, I would like to sum up all the ages for all Users named John, put that summed age back in to the instance variable so it is available to the view.
The User model has attributes 'id', 'name' and 'age'.
#foo_users = Users.where(name: 'John')
#foo_users.each do |foo|
#foo_users.age_sum = Users.where(name: 'John').sum(:age) <-- this does not work
end
I have no need to save that summed age back to a database, since I will only use it in one view. I would like to be able to display all the users:
<% #foo_users.each do |user| %>
User name: <%= user.name =>
Sum of ages: <%= user.age_sum %>
<% end %>
Update: I might have over simplified my example. Here is a closer to reality example.
A company owns hotels. Hotels have Rooms. Management software delivers to the company daily Hotel_Statistics via an API. For lack of a better word, these Hotel_Statistics contain the hotel_id, daily check-ins, daily check-outs. In the company's back-office Rails app that I am working on, on the page displayed there is a table of hotels with their given most recent statistics. One line would look like:
Hotel Id: 123
Daily check-ins: 50
Daily check-outs: 48
Hotel Id: 124
Daily check-ins: 35
Daily check-outs: 37
The company wants to also display the running sum of the last 30 days of check-ins (outs, net check-ins).
To accomplish this, in my controller, I find the Hotel_Statics for the most recent date (normally yesterday).
latest_stat = HotelStatistic.order('date DESC, hotel_id DESC').first
#latest_date = latest_stat.date
#recent_stats = HotelStatistic.where(date: #latest_date).order('hotel.id ASC').all
I display the details of #recent_stats in my view.
Now, I would like to display in my view the sum of the last 30 days of #recent_stats.check_ins for each Hotel. My idea was to sum up the the last 30 days of check_ins statistics for a given Hotel like:
#recent_stats.each do |stat|
#last_30_days_check_ins = HotelStatistic.where(hotel_id: stat.hotel_id).where("date >= ?", Date.today - 30).sum(:check_ins)
end
The math works, but I need a way to access the 30 day sum variable for each hotel. I was a hoping to make this easy in the view by adding the hotel 30 day sum to the #recent_stats instance variable so in my view I could do:
<% #recent_stats.each do |statistic| %>
Hotel Id: <%= statistic.hotel_id %>
Daily check-ins: <%= statistic.check_ins %>
Last 30 days check-ins: <%= statistic.last_30_days_check_ins %>
<% end %>
Does this more realistic example change anything in your suggested answers? Thanks
The type of #foo_users is ActiveRecord::Relation. Trying to add age_sum as a new attribute to an ActiveRecord::Relation object doesn't make sense because semantically age_sum is not an attribute of ActiveRecord::Relation objects. It's better to store the sum of ages in a new instance variable, for example #user_age_sum.
UPDATE
Try the following
class HotelStatistic < ActiveRecord::Base
belongs_to :hotel
end
class Hotel < ActiveRecord::Base
has_many :hotel_statistics
def last_30_days_check_ins
self.hotel_statistics.where("date >= ?", 30.days.ago).sum(:check_ins)
end
end
Keep the existing code for building #recent_stats in the controller
In the view
<% #recent_stats.each do |statistic| %>
Hotel Id: <%= statistic.hotel_id %>
Daily check-ins: <%= statistic.check_ins %>
Last 30 days check-ins: <%= statistic.hotel.last_30_days_check_ins %>
<% end %>
Using select should solve your problem:
#users = User.select("*, SUM(age) as age_sum").where(name: 'John')
Now each User in the #users array will have a age_sum property. This is not 100% ideal as the value of the property will be the same on each instance, but it will work with how you've setup your view.
Edit
It's possible to dynamically define a method on an instance manually:
#foo_users.each do |foo|
def foo.age_sum; Users.where(name: 'John').sum(:age); end;
end
However while this is possible, it would have to be a very good use case to justify the negative impact this may have (such as on how readable, efficient and maintainable the code is). There are probably much better OO ways to solve the same problem

Ruby on Rails: Saving many field types with one database entry

I have an application where the user can create a project that gets submitted into the database.
<div class="project_name">
Project Name:
<%= f.text_field :project_name,:maxlength => 30 %>
</div>
<%= label_tag :new_client, "Client:" %><br/>
<%= text_field_tag :new_client, nil, :maxlength => 30%>
Or
<%= f.select( :new_client, Project.all.map {|p| [p.new_client]}.uniq, :prompt => "Select an new_client") %>
</div>
Here they have the option to submit text for a new project name, and then have the option to select either an existing client, or enter a new one, which will get stored in the database, and will later be available in the drop down for the next project created.
I am trying to add a third option where they can pick an industry. This time however, the user can pick many industries for the one project. What would be the best way to go about this?
I was thinking having a dropdown with all the most common industries prepopulated in another table, and if the user wants another they can click a button to bring up another drop down. If the industry isn't present, the could enter one in a text field, that would get saved with that project entry, AND saved into the new industry table which would then be available for the next user.
Hopefully someone can point me in the right direction. I am new to rails, so go easy.
You should check this videos http://railscasts.com/episodes/196-nested-model-form-part-1
For this kind of situation i use recordselect gem for selecting existing objects, and then use a jquery template to add the objects to current form. But you have to do some js stuff to do this.
Instead i think you can also use a simple dropdown with :multiple => true option to select multiple objects.
The best way to do this is not very simple... but i think you should start with the rails casts complex form examples to figure out what you can do with nested forms.

Rails Forms and Associations - Adding multiple objects with a quantity form

I am new to rails, but not to programming or databases.
A BETTER PHRASING OF MY QUESTION IS IN MY ANSWER BELOW.
For simplicity in this example, I have 3 models:
User
Subscription
Default_Subscription
User has_many Subscriptions
Subscription belongs_to User
Default_Subscription has_many Subscriptions
Subscription belongs_to Default_Subscription
Default_Subscription is a pre-populated table with certain types of subscriptions.
During the subscription process, the default subscriptions are listed at one point, and there
is a quantity box alongside each one.
The user enters the quantities for each subscription and hits submit to continue on.
My question is:
How would one go about creating a new subscription for each quantity in a number form?
So you would have a list something like so:
<ol>
<%= each subscription with quantity box %>
</ol>
<%= button_to %>
When the user hits the button, how do you add up the quantity from each box and add a new subscription for each one? Do I have to use javascript to get the numbers? Do I somehow use rails forms even though this quantities are not associated with any specific database field? Any recommendations or pointing me in the right direction to figure this out on my own would be great.
This form box IS NOT A FIELD FOR ANY MODEL, it's a count for an association. Let me rephrase: Each quantity in the form boxes represent the number of NEW Subscriptions to be created. Each of these subscriptions BELONGS_TO 1 DEFAULT_SUBSCRIPTION. In essence, the number represents the number of new subscriptions ASSOCIATED WITH THAT DEFAULT SUBSCRIPTION.
I'm using rails 3.2.1, and ruby 1.8.7
Thank you
Not sure I totally understand your description, but I'll take a shot.
Use the 'form_for' function to build your form, based on an instance of #default_subscription (established in the "new" action in your controller). If there are default values in #default_subscription, will show in the fields and the user can change them as they see fit. (this assumes your DefaultSubscription model has three attributes: sub1, sub2 and sub3.)
<%= form_for #default_subscription do |f|
<%= f.label :sub1 %><br />
<%= f.number_field :sub1 %>
<%= f.label :sub2 %><br />
<%= f.number_field :sub2 %>
<%= f.label :sub3 %><br />
<%= f.number_field :sub3 %>
<% end %>
When the user clicks the submit button the contents of the form with we assembled into a hash and passed into your controller's "update" action via params[]. You can extract the subscription hash like this:
user_subscription = params[:default_subscription]
At this point you have all the numbers that the user entered into the fields in the user_subscription hash. You can now parse the hash to extract the numbers, do your math, and then create the appropriate subscriptions per the user's input. (one note: the numbers could be strings and you might need to convert them back to integers as I've shown below.)
For example, to total all the subscription values and save that total into a user's subscription:
total = 0;
user_subscription.each do |key, value|
total += value.to_i
end
new_sub = current_user.subscription.new
new_sub.total = total
new_but.save
As I said, I don't understand your description clearly, so this might not be germane, but hope it is close to what you were looking for.
Good luck.
I have figured out one way, and reading my original post again, the whole thing is really confusing because I didn't know how to say exactly what I was trying to accomplish. I must say a lot of the reason I was confused is because the form I wanted did not correspond to any model, just an association count, which is ultimately a basic html form if you want to create a bunch of new objects without having their attributes yet. I'll first clarify then show my solution.
Clarification:
I have 2 Tables:
Subscription
Default_Subscription (Pre-Populated)
Subscription belongs_to Default_Subscriptions
Default_Subscription has_many Subscriptions
A User is subscribing to my website. This process is a step by step: not everything happens on the same page.
This all happens in a subscribe_controller. Each action corresponds to a step in the process.
One of the actions is default_subscriptions. This action lists the Default_Subscriptions a User can choose from, except they do not just choose, they can enter an amount for each type of Default_Subscription they'd like.
When the Default_Subscriptions are listed on the default_subscriptions page, I wanted a form with an html number input alongside each of these Default_Subscription. When the form is submitted via a next button, I had no idea how to gather the quantities from each html input and create an array of Subscription.new, with each Subscription's default_subscription_id corresponding to the proper Default_Subscription.
One Possible Solution:
def default_subscriptions
#def_subscriptions = Default_Subscription.all
end
Lets say the page I want proceed to after all the quantities are entered on the default_subscriptions page is review_subscriptions.
Here's what I did to create the proper form to proceed to the next action in the controller:
<%= form_tag( {:controller => 'subscribe', :action => 'review_subscriptions'}, :method => 'post' ) do %>
<ol>
<% #def_subscriptions.each do |ds| %>
<li>
<%= ds.name + ' ' %>
<%= number_field_tag("subscription_counts[#{ds.id}]") %>
</li>
<% end %>
</ol>
<%= submit_tag('Next') %>
<% end %>
The trick here is that string passed to the number_field_tag. By placing a single set of square brackets at the end of the string for a field_tag method parameter, the part before the brackets is the name of the hash, and the thing in the brackets is a key in the hash, and the submit button causes the corresponding value for each key to be the value of the field. Pretty cool!
The parameters passed to the next action would contain a hash called subscription_counts, and iterating through this hash would give a corresponding new subscription amount for each default_subscription_id. Like so:
def review_subscriptions
subscription_counts = params[:subscription_counts]
subscription_counts.each do |id, amount|
counter = Integer(amount)
until counter == 0
new_subscription = Subscription.new
new_subscription.default_subscription_id = Integer(id)
#subscriptions << new_subscription # #subscriptions is an instance variable
counter -= 1
end
end
end
I'd just like to point out, the more I work with them, the more I love them; I love Rails, and I love Ruby. They are super fun and classy. An until loop... how cool is that? If you have other solutions, now that my question is more obvious, please chime in! I know others out there are trying to find some slick ways to create multiple new objects in a one to many association with a single post call like this. Technically my objects aren't saved in the database yet, but that wouldn't be to hard now.
The main reference which helped me the most in reaching this solution was:
http://guides.rubyonrails.org/form_helpers.html
If you are new to rails, and confused about forms, read this. I feel like a master now. Rails devs are really good at documenting things!

Resources