Nested models' views with Geocoder - ruby-on-rails

I'm trying to make a simple app that records your trips. In should get two locations (via nested model) and then show distance between them in /show~
Unfortunately, I can make a new trip, but I can't get the view for the distance. However, if I want to put 'location.address' it doesn't work too.
trip controller:
def index
#trips = Trip.all
#trip = Trip.new
2.times do
location = #trip.locations.build
end
end
def show
#trip = Trip.includes(:locations).find(params[:id])
end
location model:
class Location < ActiveRecord::Base
belongs_to :trip
extend Geocoder::Model::ActiveRecord
geocoded_by :address
after_validation :geocode, :if => :address_changed?
end
trip model:
class Trip < ActiveRecord::Base
has_many :locations
accepts_nested_attributes_for :locations
end
show view for trips:
<% for location in #trip.locations %>
<li><%= location.distance %></li>
<% end %>
I'd appreciate any help.
Edit:
Ok, so I found how to calculate distance between specific places, but I don't know how to add two locations from one nested model to this code?:
#distance = Geocoder::Calculations.distance_between([place1], [place2])

Related

How do I effectively preload conditional associations in Rails?

I have the following two models:
class Company < ActiveRecord::Base
has_many :employees # A company can have 1000's of employees.
end
class Employee < ActiveRecord::Base
belongs_to :company
end
One of my use cases looks like this
In the controller:
def my_action
#companies = Company.where(country: 'GB').preload(:employees)
#title = params[:title] # E.g. 'CTO'
end
In the view:
- #companies.each do |c|
= c.employees.where(title: #title).first.last_name
The problem with the above is that it will create an N+1 in the view
Now I could change the view to:
# In the view
- #companies.each do |c|
= c.employees.select{|e| e.title == #title}.first.last_name
This will solve the N+1 but it will still load out potentially 1000's of employee records even though I don't need them (I only need the ones with the right title).
I could solve that by:
class Company < ActiveRecord::Base
has_many :employees
has_many :ctos, ->{ where(title: 'CTO') }
end
# In the controller
def my_action
#companies = Company.where(country: 'GB').preload(:ctos)
end
# In the view
- #companies.each do |c|
= c.ctos.first.last_name
The problem with this however is that it would require me to add associations for every single possible type on Company.
So the question is, how can I solve this?
companies = Company.where(country: 'GB')
title = params[:title]
#company_employee = Employee.where(company: companies, title: title).group_by(&:company)
#company_employee will be hash with structure { company => [employees] }

Show weekly statistic for variables

I created a nested model for two locations. I use a method to count the distance between these two locations. I'd like to take statistics to count all the distances weekly and show it in a view like this:
Week 1 - 80 kms / Week 2 - 32 kms
Could someone help me with it?
#edit
Getting distance:
<% #distance = Geocoder::Calculations.distance_between(#trip.locations.first, #trip.locations.last) %>
Trip model:
class Trip < ActiveRecord::Base
has_many :locations
accepts_nested_attributes_for :locations
end
Location model:
class Location < ActiveRecord::Base
belongs_to :trip
extend Geocoder::Model::ActiveRecord
geocoded_by :address
after_validation :geocode, :if => :address_changed?
end
Trips controller:
def index
#trips = Trip.all
#trip = Trip.new
2.times { location = #trip.locations.build }
end
def show
#trip = Trip.includes(:locations).find(params[:id])
end
And I get the locations from a field_for form
also routes:
resources :trips
root 'trips#index'

Why am i getting a NoMethodError on this?

I have this in my config/routes.rb:
get '/:category/:region', to: 'categories#filtered_by_region'
The filtered_by_region action is as shown below:
#filtered_by_region method
def filtered_by_region
#region = Region.where(title: params[:region]).first
#category = Category.where(title: params[:category]).first
#teams = Team.where(region_id: #region.id, category_id: #category.id)
end
I have a view filtered_by_region.html.erb that looks as follows:
Region: <%= #region.title %>
Category: <%= #category.title %>
<% #teams.each do |team|%>
<%=team.title %>
<% end %>
region.rb model is as follows:
class Region < ActiveRecord::Base
has_many :teams
attr_accessible :title
end
category.rb model is as follows:
class Category < ActiveRecord::Base
has_many :teams
attr_accessible :title
end
team.rb model is as shown below
class Team < ActiveRecord::Base
belongs_to :category
belongs_to :region
end
I also have the corresponding regions, teams and categories tables already populated with data.
when i enter a url that looks like this:
http://localhost:3000/football/south_west
i get an error with the following message:
undefined method ``title' for nil:NilClass I have realized both the #region and #category are returning nil but i do not understand why. i do have a category with football title and a region with south_west title in categories and regions tables respectively.
Why don't you use find_by (if you're using Rails 4) or find_by_title (if you're using Rails 3):
def filtered_by_region
#category = Category.find_by_title(params[:category])
#region = Region.find_by_title(params[:title])
if defined?(#category) && defined?(#region)
#teams = Team.where(region_id: region.id, category_id: category.id)
else
redirect_to root_path
end
end
I think the likely issue will either be your query is not finding any records, or you'll be trying to access a collection as a record (regardless of the use of .first)

has_many :through association - can't save record with a foreign id during create action

I have a Rails 4 application and am having problems creating a new record for a has_many :through association. A couple of observations that I made while debugging:
Commenting out the checkboxes associated with the Features model, the application will create and save the venue object properly.
The update action in the venues controller works fine for the feature checkboxes.
Can somebody tell me why my application is having problems saving the associated features object (an array) when creating a new venue? Not sure if this is because the foreign key, venue_id, doesn't exist prior to the save...
Here's the code:
venues.rb
class Venue < ActiveRecord::Base
has_many :venue_features, dependent: :destroy
has_many :features, :through => :venue_features
venue_features.rb
class VenueFeature < ActiveRecord::Base
belongs_to :venue
belongs_to :feature
features.rb
class Feature < ActiveRecord::Base
has_many :venue_features, dependent: :destroy
has_many :venues, :through => :venue_features
venues\new.html.erb (Features are listed as checkboxes - use selects relevant checkboxes)
<%= hidden_field_tag "venue[feature_ids][]", nil %>
<% Feature.all.each do |feature| %>
<div class="checkbox">
<label>
<%= check_box_tag "venue[feature_ids][]", feature.id, #venue.feature_ids.include?(feature.id) %>
<%= feature.name %><br>
</label>
</div>
<% end %>
venues_controller.rb
class VenuesController < ApplicationController
def create
#venue = Venue.new(venue_params)
if #venue.save(venue_params)
flash[:success] = "Success!"
redirect_to venues_path
else
flash[:error] = "Problem!"
render 'new'
end
end
def venue_params
params.require(:venue).permit(:attribute_1, :attribute_2, :feature_type_ids => [])
end
end
I'm sure there's a cleaner solution but what I ended up doing was to update a different set of strong parameters after a successful save. The problem prob has something to do with 1) one of my parameters, :feature_type_ids, is actually an array and/or 2) :feature_type_ids is in a different model (not the venues.rb). I thought that Rails would "automagically" handle saving to differnet models since venues.rb and features.rb have been set up through a :has_many :through relationship. I'd be curious for a better solution but the following works:
class VenuesController < ApplicationController
def create
...
if #venue.save(venue_only_params)
if #venue.update_attributes(venue_params)
flash[:success] = "Success!"
redirect_to venues_path
else
flash[:error] = "Problem!"
render 'new'
end
end
def venue_params
params.require(:venue).permit(:attribute_1, :attribute_2, :feature_type_ids => [])
end
def venue_only_params
params.require(:venue).permit(:attribute_1, :attribute_2)
end
end

is there better way to count for three level nested forms

I have a nested forms like:
class House < ActiveRecord::Base
has_many :rooms
accepts_nested_attributes_for :rooms
attr_accessible :rooms_attributes
end
class Room < ActiveRecord::Base
has_one :tv
accepts_nested_attributes_for :tv
attr_accessible :tv_attributes
end
class Tv
belongs_to :user
attr_accessible :manufacturer
validates_presence_of :user
end
Now, I want to know for house.id = 1 how many rooms and tvs totally.
In the houses_controller I gave
#houses = House.all
And it's quit simple to get the room count for each house like
<% for house in #houses %>
<%= house.rooms.count %>
<% end -%>
My question is how to get tvs count? I am using this now
<%= house.rooms.map {|room| room.tvs.count}.sum %>
It works, but I am not sure this is good or not.
Is there any better way to get it?
I'd put a method in the model, trying to avoid code in the views.
class House
...
def tvs
rooms.inject(0) {|r, t| t + r.tvs }
end
end
class Room
...
def tvs
tv ? 1 : 0 # it's has_one association right now
end
end
Also, if in your controller your are loading all House's objects, and after that you are going to need the Rooms objects, you should load the houses like:
House.find :all, :include => { :rooms => :tv }
This way you are going to do 1 query, with your approach there will be 1 + N_rooms + N_tvs queries

Resources