问题
Fixed and solutions incorporated into the OP. A combination of comments by @max here and to my related posting Rails connecting to jBuilder. Edits are with // Was:
I'm trying to get values through a has_many :through
relationship. Three main databases: people, locations (which has street address and other information), and the join table, years
which links the person to a particular address on a specific date.
# models/person.rb
class Person < ApplicationRecord
has_many :years, dependent: :destroy
has_many :locations, through: :years
# models/location.rb
class Location < ApplicationRecord
has_many :years
has_many :people, through: :years
# models/year.rb
class Year < ApplicationRecord
belongs_to :location
belongs_to :person
years
links the person to a particular address on a specific date.
As I understand it the flow is that the show.html.erb
calls javascript/packs/olPersonMap.js
which then calls show_locations.json.jbuilder
. How do I pass the person.id
to jbuilder?
From views/people/show.html.erb
(class is probably not needed now, refactoring needed).
// Was: <div id="map" class="map"></div>
<div id="map" class="map" data-url="<%= person_locations_path(@person) %>"></div>
<%= javascript_pack_tag 'olPersonMap' %>
<div>
From javascript/packs/olPersonMap.js
.
// Near the top of the file
var urlJSON = $('#map').data('url') + '.json'
// and much further down in the code
new VectorImageLayer({
title: 'Where lived and worked',
imageRatio: 2,
source: new VectorSource({
// Was: url: '../people/show_locations',
url: urlJSON
format: new GeoJSON()
}),
From @max
jBuilder was in app/views/people/show_locations.json.jbuilder
, now app/views/people/locations/index.json.jbuilder
. Leaving code out as it wasn't the main problem (although it did have few errors).
And this
# app/controllers/people/locations_controller.rb
module People
class LocationsController < ApplicationController
before_action :set_person
def index
respond_to do |f|
f.json
end
end
private
def set_person
@person = Person.eager_load(:locations)
.find(params[:person_id])
@locations = @person.locations
end
end
end
and routes.rb
resources :people do
resources :locations, only: [:index], module: :people
end
In summary, how do I pass person.id to the jBuilder? Or am I going at this all wrong?
Thank you @max. I need to work on understanding what the controller is doing. Lots of moving parts. https://secure-shore-68966.herokuapp.com/people/124
is the Leaflet version. Will push this OpenLayers version after some refactoring to remove all the trial stuff.
回答1:
you can simply pass id
or complete URL of action (which I would prefer) using HTML data
attribute.
show.html.erb
<div id="person-details" data-url="<%= @person.id %>"></div>
javascript/packs/olPeopleMap.js
new VectorImageLayer({
title: 'Where lived and worked',
imageRatio: 2,
source: new VectorSource({
url: `../people/show_locations/${$('#person-details').data('id')}`,
format: new GeoJSON()
}),
回答2:
First setup a nested route that delivers the JSON you want to consume:
resources :people do
resources :locations, only: :index, module: :people
end
module People
class LocationsController
# GET /people/1/locations.json
def index
@person = Person.includes(:locations).find(params[:person_id])
@locations = @person.locations
end
end
end
Rename your view app/views/people/locations/index.json.jbuilder
.
Then setup the map container in the view:
<div id="map" class="map" data-url="<%= person_locations_path(@person) %>">
</div>
If your doing it the right way there is no reason to go near the .js.erb
nonsense that just makes a mess of everything since it makes your server get involved in the state of the client.
Don't try to put different script tags on different pages. Its not a good approach - especially if turbolinks is involved. Instead create handlers that augment different elements on the page if the are present (in this case the #map element) that go in your "static" /javascripts/packs
directory.
This keeps the seperation of concerns in place - the server just delivers data that the client consumes and it lets your javascript be concatenated, minified, cached and delivered via a CDN instead of having Rails serve up interpolated .js.erb
soup.
It also avoids turning your Rails app into a bunch of RPC style routes that just update the client.
In OpenLayers you should be able to get the element that the map is bound to through the target property of the map.
new VectorImageLayer({
title: 'Where lived and worked',
imageRatio: 2,
source: new VectorSource({
url: map.target.dataset.url,
format: new GeoJSON()
}),
回答3:
The answer is incorporated into the OP. Thank you @max.
PS. I changed olPeopleMap.js
to olPersonMap.js
as it was more logical.
回答4:
Rails runs on Server, JavaSciprt is scripting language runs on browser(client). Basically, there is no way to pass data from Rails to Javascript directly. So you need to third store to pass data between Rails and Javascript like HTML data attribute, HTML hidden filed,...
来源:https://stackoverflow.com/questions/59548291/rails-passing-variable-to-jbuilder