I am trying to make this behavior with my custom toastr notification
this is what i have
def toast(type, text)
flash[:toastr] = { type => text }
end
I call this in my controller like this
toast('success',"this is a message")
and it would output to my template like so
<% flash[:toastr].each do |type, message| %>
toastr.<%= type %>('<%= message %>')
<% end %>
however it only outputs 1 message
now here is the functionality I am trying to make, which is display multiple flash messages
http://tomdallimore.com/blog/extending-flash-message-functionality-in-rails/
it works because of the following method
def flash_message type, text
flash[type] ||= []
flash[type] << text
end
everytime you call #flash_message, it would save the flash message in an array, and I can use for each on the array to display it.
I am having trouble converting my #toast into that, #toast CURRENTLY does this
flash[:toastr] = {'success' => "this is a message"}
I would like to do this
flash[:toastr] = [{'success' => "this is a message'},{'error' => "problem!"}]
Can someone help me modify toast method to accept an array of hashes, and inserts a new hash everytime its called?
def toast(type, text)
flash[:toastr] ||= []
flash[:toastr] << { type => text }
end
Using Array#push:
def toast type, text
flash[:toastr] ||= []
flash[:toastr].push({ type => text })
end
Using append (<<):
def toast type, text
flash[:toastr] ||= []
flash[:toastr] << { type => text }
end
Related
as in title I'm trying to create helper that does that but I'm struggling. I'm getting errors or simply empty list like this:
And I want to achieve this:
There is to much logic to simply put this code in view. A results is a hash where the key is a website id and value is either an array of bookmarks ids or just bookmark id.
My code:
module WebsitesHelper
def present_search_results(results)
content_tag(:ul, class: "websites-list") do
results.each do |key, value|
website = Website.find(key)
concat(content_tag(:li, website.url, class: "website-#{key}") do
bookmarks = website.bookmarks.select do |b|
if value.is_a?(Array)
value.include?(b.id)
else
value = b.id
end
end
content_tag(:ul, nil, id: "website-#{key}") do
bookmarks.each do |b|
content_tag(:li, b.title)
end
end
end)
end
end
end
end
If you want to stick with helpers, then something like this could help:
def present_search_results(results)
content_tag(:ul, class: "websites-list") do
results.map do |website_id, bookmarks|
bookmarks = [bookmarks] unless bookmarks.is_a?(Array)
content_tag(:li, class: "website-#{website_id}") do
website = Website.find(website_id)
concat(website.url)
concat(
content_tag(:ul, class: "bookmarks-list") do
bookmarks.map do |bookmark_id|
bookmark = Bookmark.find(bookmark_id)
content_tag(:li, bookmark.title)
end.reduce(:+)
end
)
end
end.reduce(:+)
end
end
But, in my opinion, that code is not easy to read, so you could use plain html instead, like this:
def present_search_results(results)
list = "<ul class='websites-list'>"
results.each do |(website_id, bookmarks)|
bookmarks = [bookmarks] unless bookmarks.is_a?(Array)
website = Website.find(website_id)
list += "<li class='website-#{website_id}'>#{website}"
list += "<ul class='bookmarks-list'>"
bookmarks.each do |bookmark_id|
bookmark = Bookmark.find(bookmark_id)
list += "<li>#{bookmark.title}</li>"
end
list += "</ul></li>"
end
list += "</ul>"
list.html_safe
end
I like this one better, since it is easier to read. But both with output the list you want.
Weird problem. If the class at the bottom was a module, split the Json without problems, if it was only methods, also works, but the problem is.. when it is a class, it does not split the Json anymore, and returns an empty array.. however, if being a class, I do a puts the object, it actually puts it..
Any thoughts about why? How can I fix it?
I have this controller:
def index
begin
call_employee_work_locations_api
rescue => ex
render :json => {"service unavailable": "0001" }, :status => :service_unavailable
end
end
I have this service:
def call_employee_work_locations_api
auth = {:username=>ENV["USERNAME"], :password=>ENV["PASSWORD"]}
employee_locations = HTTParty.get(employee_work_Location_url , :basic_auth => auth)
#serialize_work_location(employee_locations)
serializer = EmployeeSerializer.new
serializer.serialize_work_location(employee_locations)
end
I have this builder:
json.array!(#top_locations) do |location|
json.extract! location, :name, :description, :latitude, :longitude
end
I have this class:
class EmployeeSerializer
def serialize_work_location(employee_locations)
employee_locations= JSON.parse(employee_locations)
locations=[]
employee_locations["work_locations"].each do |attributes|
location = Location.new(attributes["latitude"],attributes["longitude"],attributes["description"],attributes["name"])
locations.push(location)
end
employee_locations_selector(locations)
end
def top_office_location_selector(locations, city)
top_locations=[]
locations.each do |office|
if office.name == city[0] then top_locations.push(office) end
if office.name == city[1] then top_locations.push(office) end
end
#top_locations = top_locations
p #top_locations <--- it prints the object perfectly, but does not pass to the view, I get an empty array instead.
end
def employee_locations_selector(locations)
city = locations.each_with_object(Hash.new(0)) { |locations, counts| counts[locations.name] += 1 }.max_by{|k,v| v}
top_office_location_selector(locations, city)
end
end
The instance variable #top_locations is being set within the scope of the EmployeeSerializer class, not your controller. As such it's just a normal instance variable and so Rails knows nothing about it. You can assign the return value of #top_office_location_selector to an instance variable in the controller and it should work.
On a side note, the code would be cleaned up a lot by using #map over #each.
I'm having difficulties getting flashes to work with bootstrap_flash helper.
Here's a snippet of my code:
application.html.erb
...
<div class="container">
<%= bootstrap_flash %>
<%= yield %>
</div>
...
bootstrap_flash_helper.rb
ALERT_TYPES = [:error, :info, :success, :warning] unless const_defined?(:ALERT_TYPES)
def bootstrap_flash
flash_messages = []
flash.each do |type, message|
# Skip empty messages, e.g. for devise messages set to nothing in a locale file.
next if message.blank?
type = type.to_sym
type = :success if type.to_s == :notice.to_s
type = :error if type.to_s == :alert.to_s
next unless ALERT_TYPES.include?(type)
Array(message).each do |msg|
text = content_tag(:div, content_tag(:button, raw("×"), :class => "close", "data-dismiss" => "alert") + msg.html_safe, :class => "alert fade in alert-#{type}")
flash_messages << text if msg
end
end
flash_messages.join("\n").html_safe
end
end
and I'm calling flash[:notice] in my controller actions.
Can somebody give me a hint on this one?
Thanks!
On a first glance the last end in your code is one too many.
On a second glance there are some flaws in your code in my opinion:
(1) Avoid casting back and forth:
type = type.to_sym
type = :success if type.to_s == :notice.to_s
type = :error if type.to_s == :alert.to_s
You're casting type to a symbol, only to cast it back to a string while casting a constant symbol to a string to compare them. If you omit the to_s calls you can achieve the same thing without having to cast:
type = type.to_sym
type = :success if type == :notice
type = :error if type == :alert
(2) Use map instead of a helper variable + each:
flash_messages = []
flash.each do |type, message|
# ...
end
flash_messages.join("\n")
Instead of creating a temporary variable to turn the hash into an array, you can use Enumerable's map or collect method to create a new array:
flash.map do |type, message|
# ...
end.join("\n")
(3) Use a mappings hash to map to CSS classes:
ALERT_TYPES = {
:alert => :error, :info => :info, :notice => :success, :warning => :warning
}
By using a hash like this you can simply do a lookup for the match, instead of having several if statements to determine the correct class
content_tag(:div, message, class: "alert alert-#{ALERT_TYPES[type.to_sym]}")
Overall, this would be a far more readable, shorter and expandable solution, I think:
ALERT_TYPES = { :alert => :error, :info => :info, :notice => :success, :warning => :warning } unless const_defined?(:ALERT_TYPES)
def bootstrap_flash
flash.map do |type, message|
# Skip empty messages, e.g. for devise messages set to nothing in a locale file.
# This will leave a nil value in the resulting array
next if message.blank?
# Skip if it's not a valid alert type
# This will leave a nil value in the resulting array
type = type.to_sym
next unless ALERT_TYPES.keys.include?(type)
# return the markup for the alert
content_tag(:div, class: "alert alert-#{ALERT_TYPES[type]} fade in") do
# use safe_concat() to avoid using html_safe()
content_tag(:button, raw("×"), class: "close", data: { dismiss: "alert" }).safe_concat(message)
end
end.join('') # no need to join with \n --> this way nil values will be ignored as well
end
I'm receiving results from a web service like this:
result.body returns:
[2] pry(#<User::EmailSettingsController>)> result.body
=> {"RESULT"=>
{"MESSAGES"=>
[{"MESSAGE"=>
{"TYPE"=>"E",
"ID"=>"HRRCF_WD_UI",
"NUMBER"=>"025",
"MESSAGE"=>"U kunt maximaal \"5\" jobagents creëren 1",
"LOG_NO"=>"",
"LOG_MSG_NO"=>"000000",
"MESSAGE_V1"=>"5",
"MESSAGE_V2"=>"1",
"MESSAGE_V3"=>"",
"MESSAGE_V4"=>"",
"PARAMETER"=>"",
"ROW"=>"0",
"FIELD"=>"",
"SYSTEM"=>""}},
{"MESSAGE"=>
{"TYPE"=>"E",
"ID"=>"HRRCF_WD_UI",
"NUMBER"=>"025",
"MESSAGE"=>"U kunt maximaal \"5\" jobagents creëren 2",
"LOG_NO"=>"",
"LOG_MSG_NO"=>"000000",
"MESSAGE_V1"=>"5",
"MESSAGE_V2"=>"2",
"MESSAGE_V3"=>"",
"MESSAGE_V4"=>"",
"PARAMETER"=>"",
"ROW"=>"0",
"FIELD"=>"",
"SYSTEM"=>""}},
{"MESSAGE"=>
{"TYPE"=>"E",
"ID"=>"HRRCF_WD_UI",
"NUMBER"=>"025",
"MESSAGE"=>"U kunt maximaal \"5\" jobagents creëren 3",
"LOG_NO"=>"",
"LOG_MSG_NO"=>"000000",
"MESSAGE_V1"=>"5",
"MESSAGE_V2"=>"3",
"MESSAGE_V3"=>"",
"MESSAGE_V4"=>"",
"PARAMETER"=>"",
"ROW"=>"0",
"FIELD"=>"",
"SYSTEM"=>""}}]}}
Is it possible to create something ParseMessageObject(result.body) that returns that I can do something like this.
message_list = ParseMessageObject(result.body)
message_list.each do |message|
puts message.message
puts message.type
end
I have no idea if this is possible or how to do this any suggestions to get me started are welcome!
EDIT 1:
Created my class in lib:
class MessageParser
def self.parse(result)
end
end
This should basically do what you want, using a simple open struct to create a message class which has accessors for each of the keys in your message hash
require 'ostruct'
class MessageParser
Message = Struct.new(:type, :id, :number, :message, :log_no, :log_msg_no, :message_v1, :message_v2, :message_v3, :message_v4, :parameter, :row, :field, :system)
attr_reader :messages
def initialize(data)
#data = data.fetch("MESSAGES",[])
#messages = []
parse_data
end
private
def parse_data
#data.each do | msg |
message = Message.new
msg.fetch("MESSAGE",{}).each do |key, value|
message[key.downcase.to_sym] = value
end
#messages << message
end
end
end
parser = MessageParser.new(result.body["RESULT"])
parser.messages.each do |message|
puts message.message
puts message.type
end
Something like this should work:
class ParsedMessages
include Enumerable
attr_reader :messages
def initialize(data)
#messages = extract_messages_from_data(data)
end
def extract_messages_from_data(data)
# TODO: Parse data and return message objects
end
def each &block
#messages.each do |message|
if block_given?
block.call message
else
yield message
end
end
end
end
Now you can use all methods from Enumerable on ParsedMessages, like each, find, map etc etc.
I wrote a simple helper for my rails application:
def calendar_build
5.times do
whole_cal
end
end
def whole_cal
content_tag(:div, :class => "row") do
small_cal + big_cal
end
end
def small_cal
content_tag(:div, :class => "col-xs-2 token-text") do
concat(content_tag(:p, "15.20"))
end
end
def big_cal
content_tag(:div, :class => "col-xs-10 weite_cal") do
concat(content_tag(:input,"", class: "form-control input-sm pa"))
end
end
How you can see i try to generate 5 whole_cal:
def calendar_build
5.times do
whole_cal
end
end
But in my view this only displays 5 why? Thanks
The return value of the loop is 5.
1.9.3p194 :056 > 5.times {}
=> 5
You should probably do
def calendar_build
whole_cals = []
5.times do
whole_cals << whole_cal
end
whole_cals
end
And iterate the array in your view
Couldn't you do whole_cal*5? String multiplication works in general.
You have to add the generated html code to a variable like result, then put result as last line in your method to return the concatenated code
something like:
result = ""
5.times do
result += html code
end
result
and depending on your html code, you should replace the last line with result.html_safe