gmaps4rails1.5.1-Geocoding not working - ruby-on-rails

Location added to table. But missing latitude/longitude. So no marker added to the map.
class Location < ActiveRecord::Base
validates :priority,:addr,:presence=>true
validates :priority,:numericality=>{:greater_than_or_equal_to =>1,:less_than_or_equal_to =>6}
default_scope :order=>'priority'
acts_as_gmappable :lat=>'lat',:lng=>'lng'
def gmaps4rails_address
self.addr
end
def gmaps4rails_infowindow
"<h4>Target priority: #{priority}</h4>" << "<h4>Address: #{addr}</h4>" << "<h4>Latitude: #{lat}</h4>" << "<h4>Longitude: #{lng}</h4>"
end
def gmaps4rails_marker_picture
{
"picture" => "/images/#{priority%7}.jpg",
"width" => "30",
"height" => "30"
}
end
end

Simply set gmaps to false to trigger geocoding (as the doc tells)

Related

Unable to save data to a Database importing a CSV file in Ruby on Rails

I have been trying to import a .csv file on my Ruby on Rails application in order to store the data about a Peak, but failed using different methods. The application redirects to the root_url but the database remains empty. The program seems to work, at least it does not provide errors, but no data is imported into the database. This how my peaks_controller looks like:
class PeaksController < ApplicationController
def show
#peak = Peak.find(params[:id])
end
def index
#peaks = Peak.all
end
def import
Peak.import(params[:file])
redirect_to root_url, notice: "Peaks imported."
end
def new
#peak = Peak.new
end
def create
#peak = Peak.new(peak_params)
if #peak.save
redirect_to #peak
else
render 'new'
end
end
def destroy
end
private
def peak_params
params.require(:peak).permit(:name, :altitude, :prominence, :isolation, :key_col, :source, :accessibility, :land_use, :hazard, :longitude, :latitude)
end
end
This is my peak.rb class:
class Peak < ApplicationRecord
validates :altitude, presence: true
validates :prominence, presence: true
validates :isolation, presence: true
validates :key_col, presence: true
validates :source, presence: true
validates :accessibility, presence: true
validates :land_use, presence: true
validates :longitude, presence: true
validates :latitude, presence: true
#non funziona
def self.import(file)
csv = CSV.parse(File.read(file), :headers => true)
csv.each do |row|
p = Peak.new
p.id = row['id']
p.name = row['Name']
p.altitude = row['Altitude']
p.prominence = row['Prominence']
p.isolation = row['Isolation']
p.key_col = row['Key_col']
p.source = row['Source']
p.accessibility = row['Accessibility']
p.land_use = row['Land_use']
p.hazard = row['Hazard']
p.longitude = row['x']
p.latitude = row['y']
p.save
end
end
end
That just does not return anything, so it does not import anything into my database, I have also tried the following import method:
def self.import(file)
csv = CSV.parse(File.read(file), :headers => false)
csv.each do |row|
Peak.create!(row.to_h)
end
end
This is how my database looks like:
class CreatePeaks < ActiveRecord::Migration[6.0]
def change
create_table :peaks do |t|
t.string :name
t.decimal :altitude
t.decimal :prominence
t.decimal :isolation
t.decimal :key_col
t.string :source
t.decimal :accessibility
t.string :land_use
t.string :hazard
t.decimal :longitude
t.decimal :latitude
end
end
end
[And this are the headerds of the .csv file][:1]
I have inclunded "require 'csv'" on my application.rb so the application reads a csv file.
I have also tried to remove the 'id' column from the file and tried with the "row.to_h" but it did not change anything, still can't import the values onto the database.
Do you have any suggestions?
The hard part when doing a mass import is error handling - of which you're doing none. So all those calls to save the records could be failing and you're none the wiser.
You basically have two options:
1. Strict
Wrap the import in a transaction and roll back if any of the records are invalid. This avoids leaving the job half done.
class Peak < ApplicationRecord
# ...
def self.import(file)
csv = CSV.parse(File.read(file), :headers => true)
transaction do
csv.map do |row|
create!(
id: row['id'],
name: row['Name'],
altitude: row['Altitude'],
prominence: row['Prominence'],
isolation: row['Isolation'],
key_col: row['Key_col'],
source: row['Source'],
accessibility: row['Accessibility'],
land_use: row['Land_use'],
hazard: row['Hazard'],
longitude: row['x'],
latitude: row['y']
)
end
end
end
end
class PeaksController < ApplicationController
def import
begin
#peaks = Peak.import(params[:file])
redirect_to root_url, notice: "Peaks imported."
rescue ActiveRecord::RecordInvalid
redirect_to 'somewhere/else', error: "Import failed."
end
end
end
2. Lax
In some scenarios you might want to do lax processing and just keep on going even if some records fail to import. This can be combined with a form that lets the user correct the invalid values.
class Peak < ApplicationRecord
# ...
def self.import(file)
csv = CSV.parse(File.read(file), :headers => true)
peaks = csv.map do |row|
create_with(
name: row['Name'],
altitude: row['Altitude'],
prominence: row['Prominence'],
isolation: row['Isolation'],
key_col: row['Key_col'],
source: row['Source'],
accessibility: row['Accessibility'],
land_use: row['Land_use'],
hazard: row['Hazard'],
longitude: row['x'],
latitude: row['y']
).find_or_create_by(id: row['id'])
end
end
end
class PeaksController < ApplicationController
def import
#peaks = Peak.import(params[:file])
#invalid_peaks = #peaks.reject {|p| p.persisted? }
if #invalid_peaks.none?
redirect_to root_url, notice: "Peaks imported."
else
flash.now[:error] = "import failed"
render 'some_kind_of_form'
end
end
end

Rails - 5: How do I pass an array (has_many association) to the controller action

I have a model event and another model event_rule
class Event < ApplicationRecord
has_many :event_rules
end
class EventRule < ApplicationRecord
belongs_to :event
end
I have written an api event#create for saving an event. Here's the body of the POST request:
{
"name": "asd",
"code": "ad",
"isActive": true,
"description": "asd",
"notes": "",
"goalAmount": 0,
"exportId": "",
"defaultCurrency": 1,
"eventStartDate": "2017-04-25T18:30:00.000Z",
"eventEndDate": "2017-04-27T18:30:00.000Z",
"eventRules": [
{
"extraInformation": "{}",
"lookupKeyValuePairId": 40
}
]
}
Here's params hash:
Parameters: {"name"=>"asd", "code"=>"ad", "is_active"=>true, "description"=>"asd", "notes"=>"", "goal_amount"=>0, "export_id"=>"", "default_currency"=>1, "event_start_date"=>"2017-04-25T18:30:00.000Z", "event_end_date"=>"2017-04-27T18:30:00.000Z", "event_rules"=>[{"extra_information"=>"{}", "lookup_key_value_pair_id"=>40}], "client_id"=>"0", "event"=>{"name"=>"asd", "code"=>"ad", "description"=>"asd", "is_active"=>true, "goal_amount"=>0, "export_id"=>"", "event_start_date"=>"2017-04-25T18:30:00.000Z", "event_end_date"=>"2017-04-27T18:30:00.000Z", "default_currency"=>1, "notes"=>""}}
I want the 'event_rules' to be included INSIDE the event. How can do this?
def create
# initialize Event object with `event_params`
event = Event.new(event_params)
# initialize EventRule object per each `event_rule_params`, and associate the EventRule as part of `event.event_rules`
event_rules_params.each do |event_rule_params|
event.event_rules << EventRule.new(event_rule_params)
end
if event.save
# SUCCESS
else
# FAILURE
end
end
private
def event_params
params.require(:event).permit(:name, :code, :is_active, :description, :notes, :goal_amount, :export_id, :default_currency, :event_start_date, :event_end_date, :notes)
end
def event_rules_params
params.require(:event).fetch(:event_rules, []).permit(:extra_information, :lookup_key_value_pair_id)
end
Alternative Rails-way Solution:
if you have control over the parameters that get sent, reformat your request into something like the following (take note of changing event_rules into event_rules_attributes -- Rails Standard) (More Info Here)
Parameters: {
"event"=>{
"name"=>"asd",
"code"=>"ad",
"description"=>"asd",
"is_active"=>true,
"goal_amount"=>0,
"export_id"=>"",
"event_start_date"=>"2017-04-25T18:30:00.000Z",
"event_end_date"=>"2017-04-27T18:30:00.000Z",
"default_currency"=>1,
"notes"=>"",
"event_rules_attributes"=>[
{
"extra_information"=>"{}",
"lookup_key_value_pair_id"=>40
}
]
}
}
# controllers/events_controller.rb
def create
event = Event.new(event_params)
if event.save
# SUCCESS
else
# FAILURE
end
end
private
def event_params
params.require(:event).permit(:name, :code, :is_active, :description, :notes, :goal_amount, :export_id, :default_currency, :event_start_date, :event_end_date, :notes, event_rules_attributes: [:extra_information, :lookup_key_value_pair_id])
end
# models/event.rb
accepts_nested_attributes_for :event_rules

Restrict the chance to delete a booking just more than x hours before departure in Rails

I want users not to be able to cancel a booking just 2 hours before departure time.
I don't know where can I write this restriction. Should I write it in the model or in the controller application?
This is the pseudo-code I wrote so far:
class CancelValidator < ActiveMOdel::Validator
def validate(record)
if record.date_trip.to_time < Date.now + 2
record.errors[:base] << 'error'
end
end
end
EDIT: This is all the code, but it still lets me destroy the booking.. why?
class CountValidator < ActiveModel::Validator
def validate(record)
if (record.second || record.first)
record.errors[:base]<< ' error '
end
end
end
class DepartureValidator < ActiveModel::Validator
def validate(record)
if record.date_trip.to_date < Date.today
record.errors[:base]<< ' error '
end
end
end
class Reservation < ActiveRecord::Base
validates_with DepartureValidator
validates_with CountValidator
before_destroy :ensure_deletable
belongs_to :dep ,:class_name => 'Stop', :foreign_key => 'dep_id'
belongs_to :arr ,:class_name => 'Stop',:foreign_key => 'arr_id'
belongs_to :route
belongs_to :user
delegate :CountStop, :to => :route, prefix: true, :allow_nil => false
delegate :city ,:to => :arr, :allow_nil => false
delegate :city ,:to => :dep, :allow_nil => false
def division
return Reservation.select{|r| r.route_id == route_id && r.date_trip == date_trip }
end
def second
if (class_point == 2)
y=division.select{ |l| l.class_point == 2 }.count
if(y+1 > route.train.second_class_seats)
return true
end
end
return false
end
def first
if (class_point == 1)
y=division.select{ |l| l.class_point == 1 }.count
if(y+1 > route.train.prima_classe_seats)
return true
end
end
return false
end
def ensure_deletable
self.date_trip.to_time < Time.now + 2
end
end
Since you delete the value, you're going to want to add a callback instead.
The benefit of this is that, before you go and delete the entity, you can decide to stop it outright if it fails your condition.
Here's an example below. Caution: this is untested, but this should give you the gist of things.
class Booking < ActiveRecord::Base
before_destroy :ensure_deletable
private
def ensure_deletable
self.date_trip.to_time < Date.now + 2
end
end
Remember, from the documentation:
The method reference callbacks work by specifying a protected or private method available in the object...

Validate presence of shipping address unless it's same as billing address

I have this in my Order class. I want to validate the presence of shipping_address unless it's the same as the billing_address. My specs keep failing, however.
class Order < ActiveRecord::Base
attr_writer :ship_to_billing_address
belongs_to :billing_address, class_name: 'Address'
belongs_to :shipping_address, class_name: 'Address'
accepts_nested_attributes_for :billing_address, :shipping_address
validates :shipping_address, presence: true, unless: -> { self.ship_to_billing_address? }
def ship_to_billing_address
#ship_to_billing_address ||= true
end
def ship_to_billing_address?
self.ship_to_billing_address
end
end
But I keep getting failed specs (expected example not to be valid):
describe "shipping_address_id" do
context "when shipping address is different from billing address" do
before { #order.ship_to_billing_address = false }
it_behaves_like 'a foreign key', :shipping_address_id
end
end
shared_examples 'a foreign key' do |key|
it "can't be nil, blank, or not an int" do
[nil, "", " ", "a", 1.1].each do |value|
#order.send("#{key}=", value)
#order.should_not be_valid
end
end
end
Form code:
= f.check_box :ship_to_billing_address
| Use my shipping address as my billing address.
Your ship_to_billing_address method implementation is wrong. It sets #ship_to_billing_address to true even if was set to false before. This is more correct implementation:
def ship_to_billing_address
#ship_to_billing_address = true if #ship_to_billing_address.nil?
#ship_to_billing_address
end
Examples:
irb(main):001:0> class Order
irb(main):002:1> attr_writer :stba
irb(main):003:1> def stba
irb(main):004:2> #stba ||= true
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0>
irb(main):008:0* o = Order.new
=> #<Order:0x8bbc24c>
irb(main):009:0> o.stba = false
=> false
irb(main):010:0> o.stba
irb(main):011:0> class Order2
irb(main):012:1> attr_writer :stba
irb(main):013:1> def stba
irb(main):014:2> if #stba.nil?
irb(main):015:3> #stba = true
irb(main):016:3> else
irb(main):017:3* #stba
irb(main):018:3> end
irb(main):019:2> end
irb(main):020:1> end
=> nil
irb(main):021:0> o = Order2.new
=> #<Order2:0x8b737e0>
irb(main):022:0> o.stba = false
=> false
irb(main):023:0> o.stba
=> false

Active Record and file: How do i write Json file with my data?

How do I write a data in table event to json file?
Please see this code:
In model event.rb
class Event < ActiveRecord::Base
attr_accessible :name, :event_description, :start_at, :end_at, :status, :eventable_id
has_event_calendar
belongs_to :eventable, polymorphic: true
after_save :write_json
end
def write_json
Event.all.each do |event|
#eventJson = {
"id" => event.id,
"start" => event.start_at,
"end" => event.end_at,
"title" => event.name,
"body" => event.event_description,
"status" => event.status
}
end
File.open("public/event.json","w") do |f|
f.write(#eventJson.to_json)
end
end
In file Json there's one record, but in table event there are many records. How do I write all records from table event to event.json file after saving the record?
public/event.json
{"id":35,"start":"2013-03-28T00:00:00Z","end":"2013-03-28T00:00:00Z","title":"1345edrewrewr","body":"123124","status":"Confirm"}
The problem is that you assign a value to #eventJson in a loop so the previous values are lost. You should use an array:
def write_json
events_json = []
Event.all.each do |event|
event_json = {
"id" => event.id,
"start" => event.start_at,
"end" => event.end_at,
"title" => event.name,
"body" => event.event_description,
"status" => event.status
}
events_json << event_json
end
File.open("public/event.json","w") do |f|
f.write(events_json.to_json)
end
end
In this case, you might want to use map instead of each -- it's much cleaner.
Given that you said the method is in the model, this is how it would look.
class Event < ActiveRecord::Base
...
def self.write_json
record_json = self.all.map{ |record| { self.name => record.attributes } }.to_json
File.open("#{Rails.root}/#{(self.name.underscore)}.json", "w") do |f|
f.write record_json
end
end
end
You could do it in the way below:
def write_json
File.open('public/event.json', 'w') { |f| f.write(Event.all.to_json) }
end
If you want to save specific fields, you can do it in this way:
def write_json
File.open('public/event.json', 'w') do |f|
f.write(Event.select(:id, :start, :end, :title, :body, :status).to_json)
end
end

Resources