I know that this is quite a common problem but none of the other responses has been able to help me.
I am currently trying to create tests for my website but I always get the error
ActionView::Template::Error: undefined method
for quite a lot of my methods which usually result in a Nill class. The website uses devise for logging in.
Here is a test that I'm trying to run. I made sure my fixtures are loaded into the test database
require 'test_helper'
class PagesControllerTest < ActionController::TestCase
include Devise::TestHelpers
include Warden::Test::Helpers
Warden.test_mode!
def setup
sign_in User.first
end
def teardown
Warden.test_reset!
end
test "should get index" do
get :index
assert_response :success
end
test "should get voting" do
get :voting
assert_response :success
end
end
And these are the error messages when trying to run the test
Minitest::UnexpectedError: ActionView::Template::Error: undefined method `strip' for nil:NilClass
config/initializers/addChallenges.rb:22:in `findChallenges'
app/views/pages/index.html.erb:11:in `_app_views_pages_index_html_erb__190802989_69818040'
test/controllers/pages_controller_test.rb:18:in `block in <class:PagesControllerTest>'
config/initializers/addChallenges.rb:22:in `findChallenges'
app/views/pages/index.html.erb:11:in `_app_views_pages_index_html_erb__190802989_69818040'
test/controllers/pages_controller_test.rb:18:in `block in <class:PagesControllerTest>'
Minitest::UnexpectedError: ActionView::Template::Error: undefined method `strip' for nil:NilClass
config/initializers/addIdeas.rb:25:in `findIdeas'
app/views/pages/voting.html.erb:6:in `_app_views_pages_voting_html_erb___557022735_70668940'
test/controllers/pages_controller_test.rb:24:in `block in <class:PagesControllerTest>'
config/initializers/addIdeas.rb:25:in `findIdeas'
app/views/pages/voting.html.erb:6:in `_app_views_pages_voting_html_erb___557022735_70668940'
test/controllers/pages_controller_test.rb:24:in `block in <class:PagesControllerTest>'
Finished in 0.31402s
2 tests, 0 assertions, 0 failures, 2 errors, 0 skips
Process finished with exit code 0
When tracking the error in this case, this line is shown as problematic resp = http.get(url.path, headers) This is my full addIdeas code but the addChallenges one is quite similar.
class AddIdeas
#a method that will find all the challenge ideas for a user and then store them in our databse
def self.findIdeas(email,challengeId)
require "net/http"
require "uri"
require 'json'
require 'active_record'
p= People.find_by_email(email)
uri_string = 'http://sideways6.com/api/V1/Idea/Challenge/'
uri_string << challengeId.to_s
#make the http request with the headers
url = URI.parse(uri_string)
http = Net::HTTP.new(url.host, url.port)
headers = {
'Authorization' => p.basic,
'UserId' => p.userId,
'AuthorizationToken' => p.auth_tok
}
#retrieve a get response
resp = http.get(url.path, headers)
#if response is okay parse the challenge ids and add them to the person table for that user
if resp.code.to_s == '200'
if resp.body.to_s != 'null'
puts parsed = JSON.parse(resp.body)
ids = ""
parsed.each do |element|
addIdeas(element, challengeId)
ids << "#{element['IdeaId']},"
end
c = Challenges.find_by_challengeId(challengeId)
c.ideaIds = ids
c.save
end
end
end
def self.addIdeas(element, challengeId)
i = Ideas.find_by_ideaId(element['IdeaId'])
if i == nil
i = Ideas.create(:ideaId => element['IdeaId'], :title => element['Title'], :description => element['Description'], :challengeIds => challengeId, :score=>1000, :faceOff => 0, :wins =>0)
end
if i != nil
i.ideaId = (element['IdeaId'])
i.title = (element['Title'])
i.description = (element['Description'])
i.challengeIds = challengeId
i.save
end
end
def self.findAllIdeas(email)
p = People.find_by_email(email)
ids = p.challenges
splitted = ids.split(",")
counter = splitted.length
i =0
while i < counter.to_i do
findIdeas(email, splitted[i])
i += 1
end
end
end
addChallenges file
class AddChallenges
#a method that will find all the challenge ideas for a user and then store them in our databse
def self.findChallenges(email)
require "net/http"
require "uri"
require 'json'
require 'active_record'
p= People.find_by_email(email)
#make the http request with the headers
url = URI.parse('http://sideways6.com/api/V1/Challenge/All')
http = Net::HTTP.new(url.host, url.port)
headers = {
'Authorization' => p.basic,
'UserId' => p.userId,
'AuthorizationToken' => p.auth_tok
}
#retrieve a get response
resp = http.get(url.path, headers)
#if response is okay parse the challenge ids and add them to the person table for that user
if resp.code.to_s == '200'
puts parsed = JSON.parse(resp.body)
ids = ""
parsed.each do |element|
addChallenges(element)
ids << "#{element['ChallengeId']},"
end
p = People.find_by_email(email)
p.challenges = ids
p.save
end
end
def self.addChallenges(element)
c = Challenges.find_by_challengeId(element['ChallengeId'])
if c == nil
c = Challenges.create(:challengeId => element['ChallengeId'], :title => element['Title'], :description => element['Description'])
end
if c != nil
c.challengeId = (element['ChallengeId'])
c.title = (element['Title'])
c.description = (element['Description'])
c.save
end
end
def self.retrieveChallengeObject(challengeId)
c = Challenges.find_by_challengeId(challengeId)
end
end
My pages controller as requested
class PagesController <ApplicationController
def home
#current_nav_identifier = :home
end
end
Index page
<script type="text/javascript">window._token = '<%= form_authenticity_token %>';</script>
<body>
<noscript>
<div class='warning-page-cover'>
<div class='alert alert-info'>
<h2>Sorry about that, it appears that you are using a web browser without JavaScript which prevents us offering you a rich online experience.</h2>
<p>Please enable JavaScript or use a different web browser, or alternatively contact the CiCS Helpdesk for assistance.</p>
</div>
</div>
</noscript>
<%AddChallenges.findChallenges(current_user.email)%>
<%AddIdeas.findAllIdeas(current_user.email)%>
<div id='wrap'>
<nav class='navbar navbar-default navbar-fixed-top' id='main-nav'>
<div class='container-fluid'>
<div class='navbar-header'>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
</button>
<a href="<%= url_for(:controller=> 'pages', :action => 'index')%>">
<%= image_tag('/logo.png', :alt => "Sideways 6 Logo", size:"203x50") %>
</a>
</div>
<div class='collapse navbar-collapse' id="bs-example-navbar-collapse-1">
<ul class='nav navbar-nav'>
</ul>
<% if true # user_signed_in? %>
<ul class="nav navbar-nav navbar-right">
<li><%= link_to fa_icon('index', text: 'Refresh Challenges'), root_path , method: :get %></li>
<li class="dropdown">
<%= link_to '#', data: { toggle: :dropdown }, class: 'dropdown-toggle' do %>
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
<% p = People.find_by_email(current_user.email)%>
<% fName = p.firstName %>
<% if fName != nil %>
<%= fa_icon('user', text: fName )%>
<%end%>
<% if fName == nil %>
<%= fa_icon('user', text: current_user.email) %>
<%end%>
<b class="caret"></b>
<% end %>
<ul class="dropdown-menu">
<li>
<%# log out path is usually: destroy_user_session_path %>
<%= link_to fa_icon('index', text: Score.retrieveUserScore(current_user.email)), root_path , method: :get %>
<%= link_to fa_icon('challenges', text:'All Challenges'), challenges_path, method: :get, title: "See all Challenges" %>
<%= link_to fa_icon('sign-out', text: 'Log out'), destroy_user_session_path, method: :get, title: "Log out of the system" %>
</li>
</ul>
</li>
</ul>
<% end %>
</div>
</div>
</nav>
<div id="main">
<h1>Select A Challenge To Vote On</h1>
<% p = People.find_by_email(current_user.email) %>
<% ids = p.challenges %>
<% splitted = ids.split(",") %>
<% counter = splitted.length %>
<p class="lead">Please Select One</p>
<% i =0 %>
<% while i < counter.to_i do %>
<div class="row">
<div class="col-xs-12 col-md-6">
<% c = AddChallenges.retrieveChallengeObject(splitted[i]) %>
<% if Vote.canVote(splitted[i]) == true %>
<a href="<%= url_for(:controller=> 'pages', :action => 'voting')%>?challengeId=<%=(splitted[i])%>" class="challenge-select" data-challengeid="<%=(splitted[i])%>">
<div class="well clickable">
<h4><%= c.title %></h4>
<p class="text-center"> <%= c.description %> </p>
</div>
</a>
<% end %>
</div>
<% i+=1 %>
<% if i != counter %>
<div class="col-xs-12 col-md-6">
<% c = AddChallenges.retrieveChallengeObject(splitted[i]) %>
<% if Vote.canVote(splitted[i]) == true %>
<a href="<%= url_for(:controller=> 'pages', :action => 'voting')%>?challengeId=<%=(splitted[i])%>" class="challenge-select" data-challengeid="<%=(splitted[i])%>">
<div class="well clickable">
<h4><%= c.title %></h4>
<p class="text-center"><%= c.description %></p>
</div>
</a>
<% end %>
</div>
<%end%>
</div>
<% i+=1 %>
<%end%>
<%= yield %>
</div>
</div>
And voting html
<script type="text/javascript">window._token = '<%= form_authenticity_token %>';</script>
<% require 'digest/sha1'
salt = '%+5)_' %>
<% AddIdeas.findIdeas(current_user.email,params[:challengeId]) %>
<% if params[:winner] != nil
concat = "#{salt}#{params[:challengeId]}#{params[:winner]}#{params[:loser]}#{salt}"
hash = Digest::SHA1.hexdigest(concat)
if hash == params[:hash]
Score.updateScore(params[:winner],params[:loser])
Score.userScore(current_user.email)
end
end %>
<div id='wrap'>
<nav class='navbar navbar-default navbar-fixed-top' id='main-nav'>
<div class='container-fluid'>
<div class='navbar-header'>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
</button>
<a href="<%= url_for(:controller=> 'pages', :action => 'index')%>">
<%= image_tag('/logo.png', :alt => "Sideways 6 Logo", size:"203x50") %>
</a>
</div>
<div class='collapse navbar-collapse' id="bs-example-navbar-collapse-1">
<ul class='nav navbar-nav'>
</ul>
<% if true # user_signed_in? %>
<ul class="nav navbar-nav navbar-right">
<li><%= link_to fa_icon('index', text: 'Change Challenge'), root_path , method: :get %></li>
<li class="dropdown">
<%= link_to '#', data: { toggle: :dropdown }, class: 'dropdown-toggle' do %>
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
<% p = People.find_by_email(current_user.email)%>
<% fName = p.firstName %>
<% if fName != nil %>
<%= fa_icon('user', text: fName )%>
<%end%>
<% if fName == nil %>
<%= fa_icon('user', text: current_user.email) %>
<%end%>
<b class="caret"></b>
<% end %>
<ul class="dropdown-menu">
<li>
<%# log out path is usually: destroy_user_session_path %>
<%= link_to fa_icon('index', text: Score.retrieveUserScore(current_user.email)), root_path , method: :get %>
<%= link_to fa_icon('challenges', text:'All Challenges'), challenges_path, method: :get, title: "See all Challenges" %>
<%= link_to fa_icon('sign-out', text: 'Log out'), destroy_user_session_path, method: :get, title: "Log out of the system" %>
</li>
</ul>
</li>
</ul>
<% end %>
</div>
</div>
</nav>
<div id="main">
<% c = Challenges.find_by_challengeId(params[:challengeId]) %>
<% ids = c.try(:ideaIds) %>
<% splitted = ids.try(:split, ",") %>
<% shuffle = splitted.try(:shuffle) %>
<% firstIdea = shuffle.try(:first) %>
<% lastIdea = shuffle.try(:last) %>
<% f = Ideas.find_by_ideaId(firstIdea)%>
<% l = Ideas.find_by_ideaId(lastIdea)%>
<h1><%=c.try(:title)%></h1>
<p class="lead">Which best solves the challenge?</p>
<div class="row">
<div class="col-xs-12 col-md-6">
<% challengeId = params[:challengeId]
winner = f.try(:ideaId)
loser = l.try(:ideaId)
concat = "#{salt}#{challengeId}#{winner}#{loser}#{salt}"
hash = Digest::SHA1.hexdigest(concat) %>
<a href="<%= url_for(:controller=> 'pages', :action => 'voting')%>?challengeId=<%=(params[:challengeId])%>&winner=<%=(f.try(:ideaId))%>&loser=<%=(l.try(:ideaId))%>&hash=<%=(hash)%>" class="idea-vote" data-challengeid="<%=(params[:challengeId])%>" data-winner="<%=(f.try(:ideaId))%>" data-loser="<%=(l.try(:ideaId))%>" data-hash="<%=(hash)%>">
<div class="well clickable">
<h4><%= f.try(:title) %></h4>
<p class="text-center"><%= f.try(:description)%></p>
</div>
</a>
</div>
<div class="col-xs-12 col-md-6">
<% challengeId = params[:challengeId]
winner = l.try(:ideaId)
loser = f.try(:ideaId)
concat = "#{salt}#{challengeId}#{winner}#{loser}#{salt}"
hash = Digest::SHA1.hexdigest(concat) %>
<a href="<%= url_for(:controller=> 'pages', :action => 'voting')%>?challengeId=<%=(params[:challengeId])%>&winner=<%=(l.try(:ideaId))%>&loser=<%=(f.try(:ideaId))%>&hash=<%=(hash)%>" class="idea-vote" data-challengeid="<%=(params[:challengeId])%>" data-winner="<%=(l.try(:ideaId))%>" data-loser="<%=(f.try(:ideaId))%>" data-hash="<%=(hash)%>">
<div class="well clickable">
<h4><%=l.try(:title)%></h4>
<p class="text-center"><%=l.try(:description)%></p>
</div>
</a>
</div>
</div>
Skip <span class="glyphicon glyphicon-chevron-right"></span>
<%= yield %>
</div>
</div>
I have tried modifying the methods with try() and it seems to sometimes resolve the issue but after that the try() causes problems with the website itself. Sometimes the error message would redirect me to the html view file itself where methods are used.
EDIT:
Ok after fixing the headers I now get
Minitest::UnexpectedError: ActionView::Template::Error: undefined method `split' for nil:NilClass
config/initializers/addIdeas.rb:61:in `findAllIdeas'
app/views/pages/index.html.erb:12:in `_app_views_pages_index_html_erb__1448445017_66568380'
test/controllers/pages_controller_test.rb:17:in `block in <class:PagesControllerTest>'
config/initializers/addIdeas.rb:61:in `findAllIdeas'
app/views/pages/index.html.erb:12:in `_app_views_pages_index_html_erb__1448445017_66568380'
test/controllers/pages_controller_test.rb:17:in `block in <class:PagesControllerTest>'
Minitest::UnexpectedError: ActionView::Template::Error: undefined method `score' for #<People:0x000000085d17b0>
config/initializers/score.rb:50:in `retrieveUserScore'
app/views/pages/voting.html.erb:56:in `_app_views_pages_voting_html_erb___944539514_69504160'
test/controllers/pages_controller_test.rb:23:in `block in <class:PagesControllerTest>'
config/initializers/score.rb:50:in `retrieveUserScore'
app/views/pages/voting.html.erb:56:in `_app_views_pages_voting_html_erb___944539514_69504160'
test/controllers/pages_controller_test.rb:23:in `block in <class:PagesControllerTest>'
Finished in 0.53103s
2 tests, 0 assertions, 0 failures, 2 errors, 0 skips
Process finished with exit code 0
The score.rb file
class Score
def self.updateScore(winner, loser)
Math.exp(1)
w = Ideas.find_by_ideaId(winner)
l = Ideas.find_by_ideaId(loser)
# updatewinner
# games W played = get number of times the winner has matched up against other ideas
# winner new score = winner score + (1000/games W played) (1+ 1/(1 + Math.exp(loser score - winner score)))
w.faceOff += 1
w.save
lScore = l.score
wScore = w.score
wGames = w.faceOff
newWScore = wScore + (500/wGames)*(1-(1/(1 + Math.exp(lScore - wScore))))
l.faceOff += 1
l.save
lGames = l.faceOff
newLScore = lScore + (500/lGames)*(-1/(1+ Math.exp(wScore - lScore)))
puts "New Winner Score "
puts newWScore
w.score = newWScore
w.save
puts "New Loser Score "
puts newLScore
l.score = newLScore
l.save
puts newWScore
# updateloser
# games L played = get number of times the loser has matched up against other ideas
# loser new score = loser score + (1000/games L played) (1+ 1/(Math.exp(winner score - loser score)))
end
def self.userScore(email)
p = People.find_by_email(email)
score = p.score
newScore = score + 1
p.score = newScore
p.save
end
def self.retrieveUserScore(email)
p = People.find_by_email(email)
score = 'Score: ' << p.score.to_s
end
end
Ok, I did some testing:
Your error is that one of your header params is coming back from your database as nil
I can replicate your error by setting
headers = {
'Authorization' => nil,
'UserId' => nil,
'AuthorizationToken' => nil
}
and running http.get(url.path, headers)
What you can do to avoid the exception and let the API return an error is test for nil and replace it with an empty string ""
Ex: 'Authorization' => p.basic || ""
EDIT: For your edit above...
There are two errors:
ActionView::Template::Error: undefined method 'split' for nil:NilClass
This one happens because of:
ids = p.challenges
splitted = ids.split(",")
If ids is nil, you can't call split on it. You need to add a check and return at that point.
ActionView::Template::Error: undefined method 'score' for #<People:0x000000085d17b0>
Your People model doesn't have a score method
Related
I've installed the Spree Multi-Vendor gem and have built my Vendor Show page, but am getting a NameError message from the cache_key_for_vendor_products line. Here is my Vendor Controller
module Spree
class VendorsController < Spree::StoreController
before_action :load_taxon, only: :show
def index
#vendors = Spree::Vendor.active
end
def show
#vendor = Spree::Vendor.active.friendly.find(params[:id])
#searcher = build_searcher(searcher_params)
#products = #searcher.retrieve_products.where(vendor_id: #vendor.id)
end
private
def load_taxon
#taxon ||= Spree::Taxon.friendly.find(params[:taxon_id]) if params[:taxon_id].present?
end
def searcher_params
searcher_params = params.merge(include_images: true)
searcher_params[:taxon] = load_taxon.id if load_taxon.present?
searcher_params
end
def vendor_params
params.require(:spree_vendor).permit(
*Spree::PermittedAttributes.vendor_attributes,
stock_locations_attributes: Spree::PermittedAttributes.stock_location_attributes
)
end
def vendor_user_params
params.require(:spree_vendor).require(:user).permit(Spree::PermittedAttributes.user_attributes)
end
def vendor_stock_location_params
params.require(:spree_vendor).require(:stock_location).permit(Spree::PermittedAttributes.stock_location_attributes)
end
end
end
My Vendor Show
<% description = simple_format(#vendor.about_us, class: 'mb-0') %>
<% short = truncate(description, separator: ' ', length: 200, escape: false) %>
<div class="container">
<div class="row px-lg-3 mt-3 vendor-details">
<div class="col-12 text-uppercase text-center mt-4 mb-5 mb-sm-4">
<h1 class="mt-2 mb-4"><%= #vendor.name %></h1>
</div>
<div class="col-12 col-sm-6 col-lg-5 text-center pt-sm-4 pt-lg-3 pb-sm-5 vendor-details-image">
<% if #vendor.image.present? %>
<%= image_tag main_app.url_for(#vendor.image.attachment), class: 'mw-100' %>
<% end %>
</div>
<div class="col-12 col-sm-6 col-lg-5 offset-lg-1 mt-5 mt-sm-0 d-flex flex-column justify-content-center vendor-description">
<div class="vendor-details-about">
<% if description == short %>
<%= description %>
<% else %>
<div class="js-readMore">
<%= tag.div class: "js-readMore-short" do %>
<%= short %>
<% end %>
<%= tag.div class: "js-readMore-full d-none" do %>
<%= description %>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
<p><%= #vendor.contact_us %></p>
<hr/>
<div class="row">
<div class="col-12 mt-5 vendor-details-products">
<% cache(cache_key_for_vendor_products) do %>
<%= render template: #taxon ? 'spree/taxons/show' : 'spree/products/index' %>
<% end %>
</div>
</div>
</div>
And Multi Vendor Helpers located in lib/spree_multi_vendor/multi_vendor_helpers.rb
module SpreeMultiVendor
module MultiVendorHelpers
include ::Spree::ProductsHelper
include ::Spree::FrontendHelper
def cache_key_for_vendor_products
count = #products.count
max_updated_at = (#products.maximum(:updated_at) || Date.today).to_s(:number)
products_cache_keys = "spree/vendor-#{#vendor.slug}/products/all-#{params[:page]}-#{params[:sort_by]}-#{max_updated_at}-#{count}"
(common_product_cache_keys + [products_cache_keys]).compact.join('/')
end
end
end
I've gotten these codes here: https://github.com/spree-contrib/spree_multi_vendor/pull/120/files
On my vendor show page, I get this error and I can't for the life of me figure out what went wrong:
NameError in Spree::Vendors#show
undefined local variable or method `cache_key_for_vendor_products' for #<#Class:0x00007fc173a88478:0x00007fc176034b40>
Can any of you help?
ArticlesController
def home
#url = 'https://meta.discourse.org/latest.json'
#forum_data = HTTParty.get(#url).parsed_response
#topic_one = #forum_data['topic_list']['topics'][0]['title']
#topic_two = #forum_data['topic_list']['topics'][1]['title']
#topic_three = #forum_data['topic_list']['topics'][2]['title']
#topic_four = #forum_data['topic_list']['topics'][3]['title']
#topic_five = #forum_data['topic_list']['topics'][4]['title']
end
articles/home.html.erb
<div class="topics">
<ul>
<li>
<%= #topic_one %>
</li>
<li>
<%= #topic_two %>
</li>
<li>
<%= #topic_three %>
</li>
<li>
<%= #topic_four %>
</li>
<li>
<%= #topic_five %>
</li>
</ul>
</div>
I am struggling with how I can pass the integer into the object as a variable and I am also struggling with how I can create a method to move this into the model.
You can wrap it in a PORO:
class ForumTopicList
def initialize(discourse_forum_url)
#forum_url = discourse_forum_url
#forum_data = HTTParty.get(#url).parsed_response
end
def topics
#forum_data['topic_list']['topics'].map { |topic| ForumTopic.new(topic) }
end
class ForumTopic
def initialize(topic_hash)
#topic_hash = topic_hash
end
def title
#topic_hash['title']
end
end
end
This will allow you to reduce your controller to:
def home
url = 'https://meta.discourse.org/latest.json'
#topics = ForumTopicList.new(url).topics.first(5)
end
And your view can become
<div class="topics">
<ul>
<%= #topics.each do |topic|>
<li> <%= topic.title %> </li>
</ul>
</div>
I have two tables: Dimensions and Task. For each dimension have N task.
so in Task Controller i have this:
def new
#dimensions = Dimension.all
#dimensions.each do |dimension|
#task = Task.new
end
end
and the view Task this
<h1>Tasks#new</h1>
<%= form_for(#task) do |task| %>
<div class='service'>
<li class="col-md-3">
<div class="thumbnail">
<div class="caption">
<h4><%= task.name %></h4>
<p><%= task.description %></p>
</div>
<span>
</span>
</div>
</li>
</div>
<% end %>
but on the task view it shows me this error message
undefined method 'name'
undefined method 'descripcion'
try this,
def new
#dimensions = Dimension.all
#dimensions.each do |dimension|
#task = dimension.tasks.new //OR #task = dimension.build_tasks
end
end
Scenario
I have created a simple application for learning Rails and Bootstrap. What this application does is it allows users to give nicknames to celebrities and like the nicknames as well. You can check it at http://celebnicknames.herokuapp.com
I have got a link_to button for posting likes for a celebrity in my home/index.html.erb as:
<%= link_to home_updatelike_path(id: nickname.id, search: #search ), method: :post, remote: true, class: "update_like btn btn-xs btn3d pull-right" do %>
<i class="glyphicon glyphicon-thumbs-up"></i>
<% end %>
The corresponding code in my home_controller.rb for the post method is:
def updatelike
#like = Like.new(:nickname_id => params[:id], :ip_address => request.remote_ip)
#like.save
respond_to do |format|
format.html { redirect_to root_path("utf8"=>"✓", "search"=>params[:search], "commit"=>"Search") }
format.json { head :no_content }
format.js { render :layout => false }
end
end
The code in my updatelike.js.erb is as:
$('.update_like').bind('ajax:success', function() {
});
Now, what I want to achieve is to submit a like without performing a page reload.
Problem:
Whenever I press the button, the database operation is done, but the change is not reflected in the page unless I reload it. Please guide me through this noob question and also provide links to resources which explain using AJAX with Rails.
Edit
Here is the entire home/index.html.erb
<div class="jumbotron col-md-6 col-md-offset-3">
<h1 class='text-center'>Nicknamer</h1>
</div>
<div class="container">
<div class="row">
<div class="col-sm-8 col-sm-offset-2 bottom50">
<%= form_tag(root_path, :method => "get", id: "search-form", type: "search") do %>
<div class = "form-group" >
<div class = "col-sm-9 " >
<%= text_field_tag :search, params[:search], placeholder: "Name", class: "form-control" %>
</div>
<div class = "col-sm-3" >
<%= submit_tag "Search", class: "btn btn-default btn-block btn-success"%>
</div>
</div>
<% end %>
</div>
</div>
<% #names.each do |name| %>
<div class="col-md-6 col-xs-8 col-md-offset-3 col-xs-offset-2 bottom50">
<!-- ===== vCard Navigation ===== -->
<div class="row w">
<div class="col-md-4">
<% if name.sex == true %>
<%= image_tag("mal.jpg", :alt => "", class: "img-responsive") %>
<% else %>
<%= image_tag("fem.jpg", :alt => "", class: "img-responsive") %>
<% end %>
</div><!-- col-md-4 -->
<!-- ===== vCard Content ===== -->
<div class="col-md-8">
<div class="row w1">
<div class="col-xs-10 col-xs-offset-1">
<h3><%= "#{name.name}" %></h3>
<hr>
<h5>Also known as</h5>
<% name.nicknames.each do |nickname| %>
<div class = "row w2 bottom10">
<% if nickname.name_id == name.id %>
<div class="col-xs-7">
<%= nickname.nickname %>
</div>
<div class="col-xs-3 text-right">
<%= pluralize(nickname.likes.count, 'like') %>
</div>
<div class="col-xs-1">
<%= link_to home_updatelike_path(id: nickname.id, search: #search ), method: :post, remote: true, class: "update_like btn btn-xs btn3d pull-right" do %>
<i class="glyphicon glyphicon-thumbs-up"></i>
<% end %>
</div>
<% end %><!-- if -->
</div><!-- row w2 -->
<% end %><!-- do -->
<div class = "row w3 bottom30">
<%= form_for #addnickname, as: :addnickname, url: {action: "addnickname"} do |f| %>
<div class = "form-group" >
<%= f.hidden_field :name_id, :value => name.id %>
<%= f.hidden_field :search, :value => #search %>
<div class = "col-xs-9">
<%= f.text_field :nickname , :required => true, class: "form-control" %>
</div>
<div class = "col-xs-3">
<%= f.submit "Add", class: "btn btn-default btn-info"%>
</div>
</div>
<% end %>
</div>
</div><!-- col-xs-10 -->
</div><!-- row w1 -->
</div><!-- col-md-8 -->
</div><!-- row w -->
</div><!-- col-lg-6 -->
<% end %>
</div><!-- /.container -->
and this is the entire home_controller.rb
class HomeController < ApplicationController
def index
#addnickname = Nickname.new
if params[:search]
#search = params[:search]
#names = Name.search(params[:search])
else
#names = Name.all
end
end
def addnickname
#addnickname = Nickname.new(:nickname => params[:addnickname][:nickname], :name_id => params[:addnickname][:name_id])
if #addnickname.save
redirect_to root_path("utf8"=>"✓", "search"=>params[:addnickname][:search], "commit"=>"Search")
else
render :new
end
end
def updatelike
#like = Like.new(:nickname_id => params[:id], :ip_address => request.remote_ip)
#like.save
respond_to do |format|
format.html { redirect_to root_path("utf8"=>"✓", "search"=>params[:search], "commit"=>"Search") }
format.json { head :no_content }
format.js { render :layout => false }
end
end
private
def addnickname_params
params.require(:addnickname).permit(:name_id, :nickname, :search)
end
end
Ok, so you need a way to identify the div with the number that needs to change:
<div class="col-xs-3 text-right">
<%= pluralize(nickname.likes.count, 'like') %>
</div>
The easiest way to do this would be to have an id attribute on the div that corresponds to the (unique) database id of the nickname. Rails has a helper method for this called div_for. So you could change the above code to this:
<%= div_for(nickname, class: "col-xs-3 text-right") do %>
<%= pluralize(nickname.likes.count, 'like') %>
<% end %>
That will generate a div with an id like nickname_1 (if this id of the nickname is 1).
Now in your javascript template you can easily target the div that needs to be updated:
$("nickname_#{#like.nickname.id}").html(#like.nickname.likes.count);
The ajax:success binding is unnecessary here since you are rendering a javascript template. In the template you can access instance variables set in the controller - just like you can from an HTML template. The above code is meant to replace the content of the div that contains the likes count with the new count.
I have the following Code on a partial that dynamically generates a list of associated steps to a pin. Both pins and steps have image(s). Users are able to add multiple steps to a pin and then this view dynamically generates a view of these steps. For each step there are associated image(s) which I'd like to pop-up as a modal. The challenge is I keep getting the following error:
"undefined local variable or method `step' for #<#:0x00000102f498d8>"
When I stub out rendering the partial, the modal appears basically blank but works. Any ideas How do I do this?
<div class="col-md-6">
<% (0..(Step.where("pin_id = ?", params[:id]).count)-1).each do |step| %>
<div class="col-md-12">
<div class="well">
<ul class="nav pull-right">
<% if current_user == #pin.user %>
<%= link_to edit_step_path((Step.where("pin_id = ?", params[:id]).fetch(step)), :pin_id => #pin.id) do %>
<span class="glyphicon glyphicon-edit"></span>
Edit
<% end %> |
<%= link_to Step.where("pin_id = ?", params[:id]).fetch(step), method: :delete, data: { confirm: 'Are you sure?' } do %>
<span class="glyphicon glyphicon-trash"></span>
Delete
<% end %> |
<%= link_to new_step_image_path(:step_id => Step.where("pin_id = ?", params[:id]).fetch(step), :pin_id => #pin.id) do %>
Add
<span class="glyphicon glyphicon-picture"></span>
<% end %>
<% end %>
<% if StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count == 0 %>
<% else %>
| <a href="#StepImageModal" data-toggle="modal">
<span class="glyphicon glyphicon-picture"></span> (<%= StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count %> ) </strong>
</a>
<% end %>
</ul>
<strong> Step <%= step+1 %>
<p>
<%= Step.where("pin_id = ?", params[:id]).pluck(:description).fetch(step) %>
</p>
</div>
</div>
<%end %>
</div>
<div class="modal fade" id="StepImageModal">
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h3>Modal Header</h3>
</div>
<div class="modal-body">
<%= render :partial => 'pins/step_images',
:locals => { :step => step } %>
</div>
<div class="modal-footer">
Close
</div>
</div>
I don't get what you're trying to do here
Loop
As mentioned in the comments, you've got a loop which goes through your steps. However, outside the loop, you want to display the partial
The solution to your woes will either be to set an instance variable (not desired), or use another persistent data type. I'd do this:
#app/controllers/steps_controller.rb
def action
#step = {}
end
#app/views/steps/action.html.erb
<% (0..(Step.where("pin_id = ?", params[:id]).count)-1).each do |step| %>
<% #step[step.id.to_sym] = step.details %>
<% end %>
<%= render :partial => 'pins/step_images', :locals => { :step => #step } %>
unless
Some refactoring for you:
<% unless StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count == 0 %>
| <%= link_to "#StepImageModal", data: { toggle: "modal"} do %>
<span class="glyphicon glyphicon-picture"></span>(<%= StepImage.where("step_id = ?", Step.where("pin_id = ?", params[:id]).pluck(:id).fetch(step)).count %> ) </strong>
<% end %>
<% end %>