Rails: more convenient hash dumps - ruby-on-rails

When things went wrong, Rails echoes a dump of given params, it looks like this:
Parameters:
{"utf8"=>"✓",
"filter"=>{"title"=>"1",
"address"=>"2",
"city"=>{"title"=>"3"},
"people"=>{"name"=>"4",
"surname"=>"5",
"patronymic"=>"6",
"emails"=>{"email"=>"7"}},
"emails"=>{"email"=>"8"}},
"sort"=>{"0"=>{"field"=>"",
"dir"=>"asc"},
"1"=>{"field"=>"",
"dir"=>"asc"}},
"commit"=>"Show"}
But it actually would be much more useful if looks like this:
{
"utf8" => "✓",
"filter" => {
"title" => "1",
"address" => "2",
"city" => {
"title" => "3"
},
"people" => {
"name" => "4",
"surname" => "5",
"patronymic" => "6",
"emails" => {
"email" => "7"
}
},
"emails" => {
"email" => "8"
}
},
"sort" => {
"0" => {
"field" => "",
"dir" => "asc"
},
"1" => {
"field" => "",
"dir" => "asc"
}
},
"commit" => "Show"
}
How to achieve that?

With vanilla Ruby the nicest way is to turn the hash to JSON:
JSON::pretty_generate(hash_here, :allow_nan => true, :max_nesting => false)
This outputs a prettified JSON version of your object (array, hash or whatever). It won´t be pure ruby but this comes right at the base library so there is no need to install anything.

Related

Inline keyboard with values • telegram bot in Ruby

I try make feature when in chat there are some unacceptable message that any other users can reply on this message with command '/report' and admins received meesage from bot with inline keyboad where he can:
ban sender of report
ban reporter of message
So, for this I have two methods:
Action "/report" - it sends to admin inline keyboard(there is all
needed data)
"callback_query" - it processes message(don't have data what need
for ban of user) - it has only data of chat, user who clicked inline
button
Ok, i can save data from point 1 to redis and pass it into point 2, but how can I found(indenify) that variable to use it...
Any tips?
def report!(*)
Rails.cache.write(:update, update)
# create_report
# binding.pry
user_name_reporter = "#{update.dig('message', 'from', 'first_name')} #{update.dig('message', 'from', 'last_name')}"
user_name_sender = "#{update.dig('message', 'reply_to_message', 'from', 'first_name')} #{update.dig('message', 'reply_to_message', 'from', 'last_name')}"
respond_with :message, text: "We got report in the group!\n#{user_name_reporter} sent report on #{user_name_sender}", reply_markup: {
inline_keyboard: [
[
{text: t('.restrict_messages_for_sender'), callback_data: 'restrict_messages_for_sender'},
{text: t('.restrict_messages_for_reporter'), callback_data: 'restrict_messages_for_reporter'},
],
[
{text: t('.ban_for_sender'), callback_data: 'ban_for_sender'},
{text: t('.ban_for_reporter'), callback_data: 'ban_for_reporter'},
],
# [{text: t('.repo'), url: 'https://github.com/telegram-bot-rb/telegram-bot'}],
],
}
end
def callback_query(data)
report_update = Rails.cache.read(:update)
sender_user_id = report_update.dig('message', 'from', 'id')
reporter_user_id = report_update.dig('message', 'reply_to_message', 'from', 'id')
chat_id = report_update.dig('message', 'chat', 'id')
# binding.pry
case data
when 'restrict_messages_for_sender'
answer_callback_query t('.alert'), show_alert: true
bot.restrict_chat_member(chat_id: chat_id, user_id: sender_user_id, permissions: { can_send_messages: false }.to_json, until_date: (Time.now + 1.hours).to_i)
when 'restrict_messages_for_reporter'
answer_callback_query t('.no_alert')
bot.restrict_chat_member(chat_id: chat_id, user_id: reporter_user_id, permissions: { can_send_messages: false }.to_json, until_date: (Time.now + 1.hours).to_i)
when 'ban_for_sender'
answer_callback_query t('.no_alert')
bot.ban_chat_member(chat_id: chat_id, user_id: sender_user_id)
when 'ban_for_reporter'
answer_callback_query t('.no_alert')
bot.ban_chat_member(chat_id: chat_id, user_id: reporter_user_id)
end
end
data in action '/report' :
{
"update_id" => 156273636,
"message" => {
"message_id" => 523,
"from" => {
"id" => 308967324,
"is_bot" => false,
"first_name" => "PRD",
"last_name" => "RSD",
"username" => "anko20094",
"language_code" => "en"
},
"chat" => {
"id" => -686671946,
"title" => "test gropt for bots",
"type" => "group",
"all_members_are_administrators" => true
},
"date" => 1659272502,
"reply_to_message" => {
"message_id" => 522,
"from" => {
"id" => 1949490661,
"is_bot" => false,
"first_name" => "Den",
"username" => "ItshenotI",
"language_code" => "uk"
},
"chat" => {
"id" => -686671946,
"title" => "test gropt for bots",
"type" => "group",
"all_members_are_administrators" => true
},
"date" => 1659272484,
"text" => "unacceptable text, that must be reported"
},
"text" => "/report",
"entities" => [
[0] {
"offset" => 0,
"length" => 7,
"type" => "bot_command"
}
]
}
}
and here data in action 'callback_query':
{
"update_id" => 156273638,
"callback_query" => {
"id" => "1327004554721482603",
"from" => {
"id" => 308967324,
"is_bot" => false,
"first_name" => "PRD",
"last_name" => "RSD",
"username" => "anko20094",
"language_code" => "en"
},
"message" => {
"message_id" => 524,
"from" => {
"id" => 5362380113,
"is_bot" => true,
"first_name" => "anko_test",
"username" => "anko_test_bot"
},
"chat" => {
"id" => -686671946,
"title" => "test gropt for bots",
"type" => "group",
"all_members_are_administrators" => true
},
"date" => 1659272601,
"text" => "We got report in the group!\nPRD RSD sent report on Den",
"reply_markup" => {
"inline_keyboard" => [
[0] [
[0] {
"text" => "Restrict messages for sender user",
"callback_data" => "restrict_messages_for_sender"
},
[1] {
"text" => "Restrict messages for reported user",
"callback_data" => "restrict_messages_for_reporter"
}
],
[1] [
[0] {
"text" => "Ban for sender",
"callback_data" => "ban_for_sender"
},
[1] {
"text" => "Ban for reporter",
"callback_data" => "ban_for_reporter"
}
]
]
}
},
"chat_instance" => "-5057992267045364113",
"data" => "restrict_messages_for_sender"
}
}
and screenshot how it looks in telegram:in telegram

Ruby OpenStates NoMethodError - undefined method `map'

I'm having issues with a Ruby gem that used to work, but now doesn't. It's openstates https://rubygems.org/gems/openstates . The code to find Legislators doesn't seem to work anymore. We have had this code in production for a while, but are now getting this error
NoMethodError - undefined method `map' for #<String:0x007ff0b51941c0>
openstates (0.0.1) lib/openstates/model.rb:37:in `where'
This is the how we are calling the method.
OpenStates::Legislator.where(parameters)
parameters = {:state=>"Ca"}
Your code hasn't changed, the gem hasn't changed, but the API probably has.
Here's a very basic module to help you get an Array from OpenStates::Legislator.where(parameters) :
require 'open-uri'
require 'active_support/core_ext/object'
module OpenStates
class Legislator
#cache={}
class << self
def where(parameters)
url = "https://openstates.org/api/v1/legislators/?#{parameters.to_query}"
#cache[url] ||= get_json(url)
end
private
def get_json(url)
puts "# Downloading #{url}"
sleep 2
JSON.load(open(url))
end
end
end
end
parameters = {:state=>"Ca"}
p OpenStates::Legislator.where(parameters).first(2)
It outputs :
# Downloading https://openstates.org/api/v1/legislators/?state=Ca
[
{
"last_name" => "Gatto",
"updated_at" => "2016-09-24 07:16:00",
"nimsp_candidate_id" => nil,
"full_name" => "Mike Gatto",
"id" => "CAL000123",
"first_name" => "Mike",
"middle_name" => "",
"district" => "43",
"chamber" => "lower",
"state" => "ca",
"votesmart_id" => "120220",
"party" => "Democratic",
"+capitol_office" => {
"phone" => "(916) 319-2043",
"street" => "P.O. Box 942849, Room 4140",
"zip" => "94249-0043",
"city" => "Sacramento"
},
"all_ids" => [
"CAL000123",
"CAL000246",
"CAL000246",
"CAL000367"
],
"leg_id" => "CAL000123",
"active" => true,
"transparencydata_id" => "76584a5322274b9b892642b7b6ae3db5",
"photo_url" => "http://assembly.ca.gov/sites/assembly.ca.gov/files/memberphotos/AD43.jpg",
"+district_offices" => [
{
"phone" => "(818) 240-6330",
"street" => "300 East Magnolia, Suite 504",
"zip" => "91502",
"city" => "Burbank"
}
],
"url" => "http://asmdc.org/members/a43",
"country" => "us",
"created_at" => "2012-01-31 19:25:09",
"level" => "state",
"+district" => "43",
"offices" => [
{
"fax" => nil,
"name" => "Capitol Office",
"phone" => "916-319-2043",
"address" => "P.O. Box 942849, Room 5136\nSacramento, CA 94249-0043",
"type" => "capitol",
"email" => nil
},
{
"fax" => nil,
"name" => "District Office",
"phone" => "818-558-3043",
"address" => "300 East Magnolia Blvd, Suite 504\nBurbank, CA 91502",
"type" => "district",
"email" => nil
}
],
"+party" => "Democratic",
"suffixes" => ""
},
{
"last_name" => "Gordon",
"updated_at" => "2016-09-24 07:16:01",
...

How to set and get the default value in date_select rails

So i have a edit form which has year start and end date. I want to show db stored values as default dates.
I have tried this
<%= f.input :year_start_date, :label => 'Year Start Date', :as => :date_select, :include_blank => false,
:input_html => { :id => 'y_start_date'}, prompt: { day: year_start_date.day, month: Date::MONTHNAMES[year_start_date.month], year: year_start_date.year}, data: year_start_date %>
So its fine and started to show db stored values.
But the issue is when am changing only month, parameters will be
"year_start_date(1i)" => "", "year_start_date(2i)" => "3", "year_start_date(3i)" => ""
and in the controller am doing
[ school_params['year_start_date(1i)'], school_params['year_start_date(2i)'], school_params['year_start_date(3i)'] ].join('-').to_date
since it contains empty strings it throws invalid date error.
I want the default values( in this case date and year) when nothing is selected. How to achieve this?
Edit 1:
params
{
"utf8" => "✓",
"_method" => "patch",
"authenticity_token" => "abcffdgfdgfgfgf==",
"school" => {
"name" => "Test School",
"board_id" => "1",
"board_registration_number" => "",
"subdomain" => "testschool",
"email" => "",
"website" => "",
"address" => "NA",
"city" => "NA",
"pincode" => "",
"country_id" => "1",
"country_state" => "Tamil Nadu",
"phone" => "NA",
"inc_year" => "",
"handler_id" => "14451",
"year_start_date(1i)" => "",
"year_start_date(2i)" => "1",
"year_start_date(3i)" => "",
"year_end_date(1i)" => "",
"year_end_date(2i)" => "",
"year_end_date(3i)" => ""
},
"button" => "",
"controller" => "sat/schools",
"action" => "update",
"id" => "2"
}
Instead of using that ugly date/datetime input you can simply use the date picker provided by the browser without having to add additional libraries:
f.input :year_start_date, :label => 'Year Start Date', as: :string, input_html: { type: "date" }

How to group array of hashes and create nested array after keyword?

How to group array of hashes into one "groupname" and "id" hash and push elements occurring after "words" keyword into array of hashes? I can't find similar issue.
My flat input:
[{
"id" => "1",
"groupname" => "Unit 1",
"words" => nil,
"unit" => "1",
"name" => "asdfwe"
}, {
"id" => "1",
"groupname" => "Unit 1",
"words" => nil,
"unit" => "1",
"name" => "testasdf"
}, {
"id" => "2",
"groupname" => "Unit 2",
"words" => nil,
"unit" => "2",
"name" => "test2wewe"
}, {
"id" => "2",
"groupname" => "Unit 2",
"words" => nil,
"unit" => "2",
"name" => "test2sadf"
}]
Desired output:
[{
"id" => "1",
"groupname" => "Unit 1",
"words" => [{
"unit" => "1",
"name" => "asdfwe"
}, {
"unit" => "1",
"name" => "testasdf"
}]
}, {
"id" => "2",
"groupname" => "Unit 2",
"words" => [{
"unit" => "2",
"name" => "test2wewe"
}, {
"unit" => "2",
"name" => "test2sadf"
}]
}]
Current not working as expected steps:
out = []
arrhsh.each_with_index do |hsh,index|
hsh.each do |(k,v)|
if k === "words"
newhsh = {}
newhsh["id"] = hsh["id"]
newhsh["groupname"] = hsh["groupname"]
newhsh["words"] = []
wordshsh = {
"unit" => hsh["unit"],
"name" => hsh["name"]
}
newhsh["words"] << wordshsh
out << newhshq
end
end
end
out.group_by {|h| h["id"]}
What about this?
b = a.group_by { |i| i['id'] }.map do |id, group|
{
id: id,
groupname: group.first['groupname'],
words: group.map { |g| g.slice('unit', 'name') }
}
end

mongoid update all embeded objects in multiple objects

I have more then one objects. I need to update a filed in embeded objects. Here my objects.
{
"_id" : ObjectId("50dc134bb4a6de8e6b000001"),
"emails" : [
{
"_id" : ObjectId("50dc134bb4a6de8e6b000004"),
"_type" : "Email",
"name" : "personal",
"email" : "",
"current" : false
},
{
"_id" : ObjectId("51a855763183a6301e009461"),
"_type" : "Email",
"name" : "work",
"email" : "xxx#gmail.com",
"current" : true
},
],
}
{
"_id" : ObjectId("50dc134bb4a6de8e6b000002"),
"emails" : [
{
"_id" : ObjectId("50dc134bb4a6de8e6b000067"),
"_type" : "Email",
"name" : "personal",
"email" : "",
"current" : false
},
{
"_id" : ObjectId("51a855763183a6301e004795"),
"_type" : "Email",
"name" : "work",
"email" : "xxx#gmail.com",
"current" : true
},
],
}
It is a Contact collection. Here I need to set current : true where name is personal. I tried the loop function. It works fine.
contacts = Contact.where(:emails.elem_match => {"name" => "personal"})
contacts.each do |contact|
contact.email.where("name" => "personal").update_all(:current => true)
end
In mongodb we can write single line of query to update multiple objects like
db.contacts.update({"emails": {$elemMatch : {"name" : "personal"}},{ $set: {"emails.$.current":true}})
So I would like to know, Is there any possibility to write a single line of mongoid query to update multiple objects on mongoid.
An equivalent single-line Ruby statement using Mongoid is:
Contact.where(:emails.elem_match => {"name" => "personal"}).update_all("$set" => {"emails.$.current" => true})
Here's the proof that it works.
app/models/contact.rb
class Contact
include Mongoid::Document
embeds_many :emails
end
app/models/email.rb
class Email
include Mongoid::Document
field :name, type: String
field :email, type: String
field :current, type: Boolean
embedded_in :contact
end
test/unit/contact_test.rb
require 'test_helper'
require 'pp'
class ContactTest < ActiveSupport::TestCase
def setup
Contact.delete_all
end
test '0. mongoid version' do
puts "\nMongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}\nRails.version:#{Rails.version}"
end
test 'update all embedded objects' do
docs = [
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000001"),
"emails" => [
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000004"),
"_type" => "Email",
"name" => "personal",
"email" => "",
"current" => false
},
{
"_id" => Moped::BSON::ObjectId("51a855763183a6301e009461"),
"_type" => "Email",
"name" => "work",
"email" => "xxx#gmail.com",
"current" => true
},
],
},
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000002"),
"emails" => [
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000067"),
"_type" => "Email",
"name" => "personal",
"email" => "",
"current" => false
},
{
"_id" => Moped::BSON::ObjectId("51a855763183a6301e004795"),
"_type" => "Email",
"name" => "work",
"email" => "xxx#gmail.com",
"current" => true
},
],
}
]
Contact.collection.insert(docs)
# contacts = Contact.where(:emails.elem_match => {"name" => "personal"})
# contacts.each do |contact|
# contact.emails.where("name" => "personal").update_all(:current => true)
# end
#db.contacts.update({"emails": {$elemMatch : {"name" : "personal"}},{ $set: {"emails.$.current":true}})
Contact.where(:emails.elem_match => {"name" => "personal"}).update_all("$set" => {"emails.$.current" => true})
puts
contacts = Contact.all.to_a
contacts.each do |contact|
emails = contact["emails"].select{|email| email["name"] == "personal"}
assert_equal(true, emails.first["current"])
end
pp contacts.collect{|contact| contact.serializable_hash}
end
end
rake test
Run options:
# Running tests:
[1/2] ContactTest#test_0._mongoid_version
Mongoid::VERSION:3.1.6
Moped::VERSION:1.5.2
Rails.version:3.2.17
[2/2] ContactTest#test_update_all_embedded_objects
[{"_id"=>"50dc134bb4a6de8e6b000001",
"emails"=>
[{"_id"=>"50dc134bb4a6de8e6b000004",
"current"=>true,
"email"=>"",
"name"=>"personal"},
{"_id"=>"51a855763183a6301e009461",
"current"=>true,
"email"=>"xxx#gmail.com",
"name"=>"work"}]},
{"_id"=>"50dc134bb4a6de8e6b000002",
"emails"=>
[{"_id"=>"50dc134bb4a6de8e6b000067",
"current"=>true,
"email"=>"",
"name"=>"personal"},
{"_id"=>"51a855763183a6301e004795",
"current"=>true,
"email"=>"xxx#gmail.com",
"name"=>"work"}]}]
Finished tests in 0.083133s, 24.0578 tests/s, 24.0578 assertions/s.
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

Resources