Rails change a variable based on button push - ruby-on-rails-3

I have a weekly spreadsheet type display of hours for an employee. It displays this week fine. But, I'd like them to be able to go forward a week or back a week.
The working display code is:
<% showdate = DateTime.now%>
<td><strong><%= showdate.beginning_of_week.to_date - 1.day%></strong></td>
<td><strong><%= showdate.beginning_of_week.to_date %></strong></td>
<td><strong><%= showdate.beginning_of_week.to_date + 1.day %></strong></td>
<td><strong><%= showdate.beginning_of_week.to_date + 2.day %></strong></td>
<td><strong><%= showdate.beginning_of_week.to_date + 3.day %></strong></td>
<td><strong><%= showdate.beginning_of_week.to_date + 4.day %></strong></td>
<td><strong><%= showdate.beginning_of_week.to_date + 5.day %></strong></td>
I have a button group:
<div class="btn-group-wrap">
<button class="btn btn-primary">- 1</button>
<button class="btn btn-success">+ 1</button>
When the user presses the -1 button, I would like to change the showdate to -1.week and refresh the page.
How would I accomplish that?

Your assignment of showdate could be <% showdate = DateTime.now + (params[:offset].to_i.weeks %> and then the +1 button could go to http://your/url?offset=<%= params[:offset].to_i + 1 %>.

Related

Rails + Minitest + Capybara: how to assert_select with span id

in my view i have:
<span class = "info">
<span id="<%= account.id %>" data-account_id="<%= account.id %>" data-activated="<%= account.starts_at? %>">
<%= t(".account_activated") %>
</span>
</span>
What is the best way to test (system test with use of capybara) if there is "account has been activated" text displayed inside ?
I tried:
assert_selector "span##{acount.id}", text: "account has been activated"
but get Selenium::WebDriver::Error::InvalidSelectorError: invalid selector: An invalid or illegal selector was specified
In HTML5 the definitions were changed to allow ids to start with numbers, but CSS requires leading numbers to be escaped correctly (#\31 234 would match an id of '1234'). Because of this if you need to match an element by CSS with an id that may start with a number it's best to use the id option (supported by all Capybara selectors) and let Capybara merge it into the CSS
assert_selector "span", id: account.id, text: "account has been activated"
which will correctly escape and apply it to the CSS. If you just want to specify the id and not the element type(since the id should be unique on the page) you can use the :id selector type (rather than the default CSS selector type)
assert_selector :id, account.id, text: "account has been activated"
I've solved this issue.
This is because ID's should not begin with numbers (see here)
ID and NAME tokens must begin with a letter ([A-Za-z]) and may be
followed by any number of letters, digits ([0-9]), hyphens ("-"),
underscores ("_"), colons (":"), and periods (".").
View code should be changed as follows:
<span class = "info">
<span id="**account_**<%= account.id %>" data-account_id="<%= account.id %>" data-activated="<%= account.starts_at? %>">
<%= t(".account_activated") %>
</span>
</span>
and
assert_selector "#account_#{account.id}", text: "account has been activated"

awesome_nested_set with optgroup labels

I am using the awesome_nested_set gem located here https://github.com/collectiveidea/awesome_nested_set. I would like to make the parent categories optgroup labels but am at a loss on how to make that happen or if it is even possible. Is there an example somewhere of this behavior?
This is certainly not the most efficient way to do this, but it met the requirement of the task.
<select name="category_id" data-placeholder="Select a Category" class="chzn-select">
<option value=""></option>
<% #cats.each do |cat| %>
<optgroup label="<%= cat.name %>">
<% cat.children.each do |child| %>
<option value="<%= child.id %>"><%= child.name %></option>
<% end %>
</optgroup>
<% end %>
</select>
A little late, but I had the same question and solved it by using a helper method according to https://github.com/collectiveidea/awesome_nested_set/blob/master/lib/awesome_nested_set/helper.rb
module ApplicationHelper
def grouped_nested_set_options(class_or_item, mover = nil)
if class_or_item.is_a? Array
items = class_or_item.reject { |e| !e.root? }
else
class_or_item = class_or_item.roots if class_or_item.respond_to?(:scope)
items = Array(class_or_item)
end
result = []
group = []
items.each do |root|
root.class.associate_parents(root.self_and_descendants).map do |i|
if i.level == 0
group = []
group.push yield(i)
group.push []
result.push group
else
if mover.nil? || mover.new_record? || mover.move_possible?(i)
group[1].push [yield(i), i.primary_id]
end
end
end.compact
end
result
end
end
That way you can just use grouped_nested_set_options instead of nested_set_options and you can still use rails' form helpers for generating the html.

Rails 3 - how to save (un)checked checkboxes?

I have in a form (form_tag) several checkboxes like this:
<%=check_box_tag 'model_name[column_name]', 1, (#data.model_name.column_name == 1 ? true : false)%>
And updating them like:
variable = ModelName.find(params[:id])
variable.update_attributes(params[:model_name])
This works only in a moment, when I check some checkboxes - send them and they will be saved. That's fine.
But when I uncheck all checkboxes - send form - so nothing happend, in the DB table will not set the value 0 in the columns...
Could you give me any tip, how to fix it?
Thank you in advance
This happens because an unchecked checkbox will not send any value to the server. To circumvent this Rails provides the check_box helper, which generates code like this:
<input type="hidden" name="model[attr]" value="0" />
<input type="checkbox" name="model[attr]" value="1" />
Alternatively, insert a hidden field with hidden_field_tag:
<%= hidden_field_tag 'model_name[column_name]', '0' %>
<%= check_box_tag 'model_name[column_name]', 1, (#data.model_name.column_name == 1 ? true : false) %>

Send to multiple recipients in Rails with ActionMailer

I'm trying to send multiple emails based on a boolean value in my database. The app is a simple scheduling app and user can mark their shift as "replacement_needed" and this should send out emails to all the users who've requested to receive these emails. Trouble is, it only every seems to send to one email. Here's my current code:
def request_replacement(shift)
#shift = shift
#user = shift.user
#recipients = User.where(:replacement_emails => true).all
#url = root_url
#recipients.each do |r|
#name = r.fname
mail(:to => r.email,
:subject => "A replacement clerk has been requested")
end
end
In the Rails guides (Action Mailer Basics) it says the following regarding multiple emails:
The list of emails can be an array of email addresses or a single string with the addresses separated by commas.
So both "test1#gmail.com, test1#gmail.com" and ["test1#gmail.com", "test1#gmail.com"] should work.
See more at: http://guides.rubyonrails.org/action_mailer_basics.html
You can just send one email for multiple recipients like this.
def request_replacement(shift)
#shift = shift
#user = shift.user
#recipients = User.where(:replacement_emails => true)
#url = root_url
emails = #recipients.collect(&:email).join(",")
mail(:to => emails, :subject => "A replacement clerk has been requested")
end
This will take all your #recipients email addresses and join them with ,. I think you can also pass an array to the :to key but not sure.
The only problem is you won't be able to use #name in your template. :(
I have the same problem. I don't know what is the deal is. I sidestep it by:
instead of calling
Mailer.request_replacement(shift).deliver
from my controller,
I'd define a class method on the mailer, and call that. That method would then iterate through the list and call deliver "n" times. That seems to work:
class Mailer
def self.send_replacement_request(shift)
#recipients = ...
#recipients.each do |recipient|
request_replacement(recipient, shift).deliver
end
end
def request_replacement(recipient, shift)
...
mail(...)
end
end
and from the controller, call
Mailer.send_replacement_request(shift)
To prevent each recipient from seeing the other email addresses:
#recipients.each{ |recipient| Mailer.request_replacement(recipient, shift).deliver }
I'm using Rails 5 and I have the same situation, the email was sent only to the last recipient but also it was sent just as plain text not as HTML email.
After trying some advices, I ended up fixing it in this way:
The mailer:
class BrochureMailer < ApplicationMailer
default from: "info#site.com"
def newsletter(sponsor, brochures_list)
#sponsor = sponsor
#brochures = brochures_list
mail(
to: #sponsor.email,
subject: "Interesting subject!"
)
end
end
The controller where the mailer is invoked:
class Admin::DashboardController < Admin::BaseController
def send_newsletter
sponsors = params[:sponsor_ids]
brochures = params[:brochure_ids]
sponsors = Sponsor.where(id: sponsors)
brochures = Brochure.where(id: brochures).to_a
# Send Newsletter email to the given Sponsors
sponsors.each do |sponsor|
BrochureMailer.newsletter(sponsor, brochures).deliver_later
end
redirect_back(fallback_location: admin_root_path, success: 'Newsletter sent!')
end
end
And in the view, something like this:
<% #brochures.each do |brochure| %>
<table width="280" border="0" cellpadding="0" cellspacing="0" align="left" valign="top" class="floater">
<tr>
<td align="center" valign="top">
<a target="_blank" href="<%= brochure_url(brochure) %>">
<img border="0" vspace="0" hspace="0" src="<%= brochure.image.blank? ? 'default.png' : brochure.image.url(public: true) %>" width="250" height="142">
<b><%= brochure.title %></b>
</a>
<br>
<%= brochure.description.truncate(60) %>
</td>
</tr>
</table>
<% end %>
And it works like a charm!
I'm not sure if this is the correct way or the most optimal way to go but just consider it as a second possibility.
I hope it could be useful for somebody else.

need to create a helper for rails 3

I need to create some type of helper for a form where it will create a select for each day of the week.
Below, creates the 5 instances, but only submits the last one.
def basic_question(q)
a = ""
5.times do
a << select("question[question_id_#{q.id}]", :response, (0..30).to_a) + " for #{q.survey.publish_on.strftime('%A')} #{q.survey.publish_on.strftime('%D')} <br />"
end
return a.html_safe
end
EDIT
Here is the view to take the survey
<%= form_for store_survey_path(#survey) do |f| %>
<% hidden_field.user_id, :value => current_user.id %>
<% #survey.questions.each do |q| %>
<li><%= q.content %></li>
<%= question_helper(q) %>
<% end %>
<p><%= f.submit %></p>
<% end %>
And the helper that checks for the type of question it is.
def question_helper(question)
case question.question_type
when 'basic'
return basic_question(question)
when 'fill_in'
return fill_in_question(question)
when 'scale_5'
return "should return a scale of 5"
when 'scale_10'
return "should return a scale of 10"
when 'must_choose_answer'
return question.answers.to_s
when 'just_label'
return " I will be a label"
else
return "Couldn't find in helper"
end
end
You could either go with giving the separate selects different names so that they are submitted separately, or you could submit them all as an array. I would go with the last option.
To submit them as an array, you have to add [] to the end of the select name like this:
question[question_id_#{q.id}][]
Which would end up looking like this:
a << select("question[question_id_#{q.id}][]", :response, (0..30).to_a) + " for #{q.survey.publish_on.strftime('%A')} #{q.survey.publish_on.strftime('%D')} <br />"
I hope that helps.