Reputation: 33775
I have a ProfilesController
that has the following:
if @profile.ratings
@rating = @profile.ratings.find_by(user: current_user)
end
When the page is just loaded, before it even sends a request back to the controller, for it to respond_to
, I would like to access that @rating
instance variable in my app/assets/javascripts/profiles.js.erb
file like so:
console.log('<%= @rating %>');
It just returns as nil
now.
How do I get access to that @rating
instance variable in that profile.js.erb
on the first load?
Edit 1
For some clarity and more context, this is what is happening.
I have some JS powered UISliders
that look like this:
The HTML that generates this is (along with more like it) - Profile#Show.html.erb
:
<td>
<p>
<button type="button" class="btn btn-danger m-r-sm slider-step-value" id="slider-step-value-speed-<%= @profile.slug %>">5</button>
Speed
</p>
<div id="slider-speed" class="slider"></div>
</td>
<td>
<p>
<button type="button" class="btn btn-primary m-r-sm slider-step-value" id="slider-step-value-tackling-<%= @profile.slug %>">3</button>
Tackling
</p>
<div id="slider-tackling" class="slider"></div>
</td>
This is the JS - app/assets/javascripts/profiles.js.erb
- that corresponds to that HTML:
var sliders = $('.slider');
var buttons = $('.slider-step-value');
for ( var i = 0; i < sliders.length; i++ ) {
var button = $(sliders[i]).prev('p').find('button')[0];
var _slider_type = sliders[i].id.split('-')[1];
console.log(_slider_type);
console.log('<%= @rating %>');
noUiSlider.create(sliders[i], {
start: 5,
step: 1,
behaviour: 'tap',
connect: [true, false],
range: {
'min': 1,
'max': 10
}
});
attachEvent(sliders[i], button);
}
function attachEvent(slider,button){
slider.noUiSlider.on('update', function( values, handle ) {
button.innerText = parseInt(values[handle]);
var _profile_id = button.id.split('-').slice(4).join('-');
var _rating_type = button.id.split('-')[3]
var url = "/profiles/" + _profile_id + "/" + _rating_type + "_rating/?" + _rating_type + "=" + button.innerText
$.ajax({
type: "PATCH",
url: url,
success: function(){
// console.log(_profile_id + "'s " + _rating_type + " was successfully updated.");
},
error: function(){
// console.log(_profile_id + "'s " + _rating_type + " was NOT successfully updated.");
}
})
});
}
This is my ProfilesController#Show
action:
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy, :invite_user, :speed_rating, :tackling_rating, :dribbling_rating, :passing_rating]
authorize_resource except: [:dashboard, :speed_rating, :dribbling_rating, :tackling_rating, :passing_rating]
skip_authorization_check only: [:dashboard, :speed_rating, :dribbling_rating, :tackling_rating, :passing_rating]
def show
if @profile.ratings
@rating = @profile.ratings.find_by(user: current_user)
end
end
end
So the issue is that on the first load, what happens is the HTML loads the default values that are hardcoded in the HTML (I will eventually change this to the normal db-values, that's straightforward). Then after the JS is loaded, this noUiSlider
script updates both the value of the button
tag (aka the colorful box) and the position of the slider.
The way it does that is at this line:
noUiSlider.create(sliders[i], {
start: 5,
So rather than just defaulting to 5
, I want it to pull @rating
from my Profiles#Show
controller, so something like start: <%= @rating %>
. That would automagically update both the Slider & button
(aka colorful box) like I want.
The issue is on the first page load, @rating
is nil/empty. So that's what I am struggling with.
Perhaps I need to send a get
request, but I am unsure about how to approach this.
Edit 2
For the record, the AJAX call works and updates the DB like I expect. That happens when I move the slider, AFTER it has initially loaded though. So the issue is on the first page load only, I need the slider & button
to be updated if there is a value in @rating
.
Upvotes: 0
Views: 563
Reputation: 33775
I figured it out.
Basically the best way for me to approach this was to add a data
attribute to each of the button
tags that pull from the db on initial load.
So while my old button
tag looked like this:
<button type="button" class="btn btn-danger m-r-sm slider-step-value" id="slider-step-value-speed-<%= @profile.slug %>">5</button>
My new button
tag looks like this:
<button type="button" class="btn btn-danger m-r-sm slider-step-value" id="slider-step-value-speed-<%= @profile.slug %>" data-speed-value="<%= speed_rating %>"><%= speed_rating %></button>
Where speed_rating
is a helper method defined in my profiles_helper.rb
that looks like this:
def speed_rating
if @rating.speed
@rating.speed
else
"5"
end
end
Then, in my JS, all I did was select that data
attribute for each button like this:
var button = $(sliders[i]).prev('p').find('button')[0];
var _slider_type = sliders[i].id.split('-')[1];
var _original_value = $('button#' + button.id).data(_slider_type + "-value");
The only new line was this:
var _original_value = $('button#' + button.id).data(_slider_type + "-value");
Then I just add that to my noUiSlider.create
call, so now it looks like this:
noUiSlider.create(sliders[i], {
start: _original_value,
As opposed to it originally looked like this:
noUiSlider.create(sliders[i], {
start: 5,
And voila....works like magic!
Upvotes: 1
Reputation: 230461
If you need to access that variable from profiles.js.erb
, put its calculation into profiles
action of the corresponding controller. Currently, it's calculated in another action and, naturally, not available in profiles
.
Upvotes: 0
Reputation: 705
Your question doesn't make a lot of sense to me, because you've said you're trying to render @rating, but then you wrote code that renders '<%= @profile.ratings %>'. Also, the if statement you shared suggests that sometimes that field is nil. I'll see what I can do but I think you need to post more information.
I'm imagining you have a page like this:
<%# profile.html.erb %>
<div id="profiles">
...
<button data-remote="true" >Load ratings</button>
</div>
and then when you click this button, it sends a request to your controller with :js format, which loads your profile.js.erb.
There must be a controller action displaying any text. If you're looking at an HTML page from rails, there is some controller action somewhere. You need to add the @rating instance variable to that controller action, and render it in the corresponding view.
Could you post:
Upvotes: 0