The problem that I'm having is that any instance variables that I declare in my show function of Charges Controller, appears as nil in the view. If I set an instance variable to a number, it doesn't even appear in the view. My home function works perfectly with instance variables.
This is my Controller with the Home and Show functions:
class ChargesController < ApplicationController
def home
#products = Product.all
end
def show
#product = Product.find_by(id: params[:id])
end
This is my View for the Show function(show.html.erb):
<h1>Product Details</h1>
<h3> <%= #product.name %> </h3>
<h4> <%= #product.price %> </h4>
<h5> <%= #product.description %> </h5>
This is my view for the Home function that contains the button that directs to the show page(home.html.erb)
<h1>Products</h1>
<% #products.each do |product| %>
<br>
<p> <%= product.name %>: $<%= product.price %> </p>
<p> <%= product.description %> </p>
<%= button_to "Product Details", charge_path(product.id), :method => "get" %>
<br>
<%end%>
error message I'm receiving
find_by method returns nil if it does not find the record. So that means the product id(params[:id]) you searching in your Product model is not found.
You can check it manually in the rails console.
Type rails c in your terminal then try the bellow code
Product.find_by(id: the_id_you_want_to_search)
Alternatively you can use find method. It raises an exception when it does not find the record.
def show
#product = Product.find(params[:id])
end
By default ,its always find by id,So kindly use only..
def show
#product = Product.find params[:id]
end
Moreover,you can check in rails console using rails c to verify that the record is present with that id using,for example Product.find 18.
Also check the url which should match with your routes..for example../users/:id for get request Only mapped to users#show action.
Get local copy of your routes using rake routes > path.text and use it as reference
In your home.html.erb try change this
<%= button_to "Product Details", charge_path(product.id), :method => "get" %>
to
<%= link_to "Product Details", charge_path(product.id) %>
Then if it does not work, try to raise the params or the instance in your show method
def show
raise params.inspect
#product = Product.find params[:id]
end
or
def show
#product = Product.find params[:id]
raise #product.inspect
end
Those were some simple ways to check whats happening in your code.
Related
I have a Rails app that searches through a DB and returns items. At the moment in my view it automatically returns the default search results ("") without me needing to hit my submit_tag. How do I go about only making this action happen once I have hit the submit_tag? Any help would be greatly appreciated!
Here is my view:
<%= form_tag(new_design_path, method: :get) do %>
<%= label_tag(:q, "Search all designs:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %><br>
<!-- Button to return one random design -->
<%= form_tag(new_design_path, method: :get) do %>
<%= label_tag(:q, "Inspire me! Click here for a random design:") %>
<%= submit_tag("Random Design") %>
<% end %>
<h2>Search results:</h2>
<% #random.each do |design| %>
<h3><%= design['name'] %></h3>
<h5><%= image_tag design['thumbnail_url'] %></h5>
<% end %>
<% #search.each do |design| %>
<div class="design">
<h3 class="design_name"><%= design['name'] %></h3>
<h5><%= image_tag design['thumbnail_url'] %></h5>
<%= button_to 'Save to Favourites',
designs_path(
design: design.slice('name', 'thumbnail_url')
),method: :post %>
</div>
<% end %>
And my controller:
class DesignsController < ApplicationController
def index
#designs = Design.all.order("created_at DESC")
end
def new
# returns an array of hashes
#search = SpoonflowerApi.new.find(params[:q])['results']
#random = SpoonflowerApi.new.random(rand(1..740579), 1)['results']
end
def create
#design = Design.new(design_params)
#design.save
if #design.save
flash[:notice] = 'Design has been added to favourites!'
else
flash[:notice] = 'Design already in Favourites!'
end
redirect_to new_design_path
end
def destroy
#design = Design.find(params[:id])
#design.destroy
flash[:notice] = 'Design removed from favourites!'
redirect_to designs_path
end
private
def design_params
params.require(:design).permit(:name, :thumbnail_url)
end
end
new is used to populate the initial form, so if you don't want anything for those fields you should just set both #search and #random to an empty array in new. You don't show any code for your model, so it's not really clear what Api is.
show should be called once you submit the form
def new
#search = []
#random = []
end
then move the logic to provide the search results or random record into the show method
def show
# not sure what you want to do here
# since it seems like you have 2 buttons you need logic to provide data
# based on the button
# maybe something like this
if params[:q].nil?
#search = []
#random = Api.new.random(rand(1..740579), 1)['results']
else
#search = Api.new.find(params[:q])['results']
#random = []
end
end
If I understood you correctly, your view showing some search results before you click the search button.
Since you directly send the params[:q] to SpoonflowerApi, I am guessing that it returns some default value and your view draw it.
Simply update your controller to:
def new
#search=[]
#search = SpoonflowerApi.new.find(params[:q])['results'] unless params[:q].nil?
#random = SpoonflowerApi.new.random(rand(1..740579), 1)['results']
end
I am trying to make the vote total editable from a JSon parsed API. I have the following in my rosters controller:
def index
#rosters = HTTParty.get('https:api', :headers =>{'Content_Type' => 'application/json'})
#allrosters = Roster.all
#allrostershash = {}
#allrosters.each do |roster|
image_url = roster['image_url']
#allrostershash[ image_url ] = roster
end
#rosters.each do |roster|
img_url = roster['image_url']
unless #allrostershash[img_url]
Roster.create(roster)
end
end
end
def count_vote
roster_id = params[:id]
roster = Roster.find_by(roster_id)
newvote = roster.vote + 1
if roster.update({vote: newvote})
redirect_to rosters_path
end
end
Roster is the name of my class above. In my rails views I have the following:
<% #rosters.each do |roster| %>
<div class='each'>
<%= image_tag(roster['image_url'], class: 'image') %>
<%= hidden_field_tag(roster['id']) %>
<p class='name'> <%= roster['name'] %> </p>
<p class='title'> <%= roster['title'] %> </p>
<p> <%= roster['bio'] %> </p>
<p> <b> Want to work with <%= roster['name'] %>? </b> <%= link_to image_tag('yes.jpg', class: 'yes'), rosters_path, method: :patch %>
<br>
<%= roster['vote'] %> People have said Yes! </p>
<br>
</div>
<% end %>
I would like that every time someone clicks on yes.jpg, the roster['vote'] increases by 1.
Currently my routes are set up as follows:
get 'rosters', to: 'rosters#index'
patch 'rosters', to: 'rosters#count_vote'
I'm trying to accomplish this without jquery or ajax, that's why I have the if roster.update portion to redirect to rosters_path, so it basically refreshes the page upon click. Right now it isn't updating the vote total however, I'm not sure what I'm missing. I would like to do it all on a single page so if its not possible without JQuery, any guidance in right direction is appreciated.
count_vote will silently fail if it cannot find your Roster or if the update cannot be saved. Change it so it raises an exception of anything fails.
def count_vote
roster = Roster.find(params[:id])
roster.vote += 1
roser.save!
redirect_to rosters_path
end
find will raise RecordNotFound if the Roster cannot be found. save! will raise an error if the changes cannot be saved.
These are the only params currently for some reason ActionController::Parameters {"_method"=>"patch", "authenticity_token"=>"qbORnCLNnI9P1zUZ02VEP3qJMwYOGa5sGw6KblPFj99mvjwZQj9VnDQ2e+6ZStJi3PJZ3MidSMsdoWlwOgBN9w==", "controller"=>"rosters", "action"=>"count_vote"} permitted: false> how would I add an id param? – Sohel 5 hours ago
I'm not very familiar with how views work, but I think as in this example, I believe you need to pass the roster into rosters_path.
<%= link_to image_tag('yes.jpg', class: 'yes'), rosters_path(roster), method: :patch %>
Similarly, if you want count_vote to redirect back to the roster you just changed...
redirect_to rosters_path(roster)
I am trying to make a very simple vocabulary webapp that shows a bunch of words with their definitions on the front (index) page. Each word has a field called "knowledge," the value of which can either be "learning" or "learned."
I would like to put a link at the bottom of the index page called "Practice." Clicking on the link will take you to a page showing the word and definition of the first word in the knowledge: "learning" column. Then there will be a "next" link that takes you to the next word in the knowledge: "learning" column. When you run out of words in the knowledge: "learning" column, you're taken back to the index page.
I am getting an id => nil error. The problem appears to be that clicking on the practice link sends me to a show page which requires an id, however I do not actually query the database to determine the id of the first word until I reach the show action in the controller. How do I make a link to "show" the first word in a column?
The "practice" link on the index page looks like this:
<%= link_to 'Practice', page_path(#page) %>
I am using resources :pages in the routes file.
My the show action in my controller Pages looks like this:
def show
if #page.nil?
#page = Page.where(knowledge: 'Learning').first
else
#next = Page.where("id > ?", params[:id]).order(:id).first
end
end
Finally, my show page looks something like this:
<% if #page%>
<p> <%= #page.word %></p>
<p> <%= #page.content %></p>
<p><%= link_to "Next", page_path(#next) %></p>
<% elsif #next %>
<p> <%= #next.word %></p>
<p> <%= #next.content %></p>
<p><%= link_to "Next", page_path(#next) %></p>
<% else %>
<p> Good Job!</p>
<p><%= link_to "Home", pages_path %> </p>
<%end%>
Error message is:
No route matches {:action=>"show", :controller=>"pages", :id=>nil} missing required keys: [:id].
The error highlights this line from my index template:
<%= link_to 'Practice', page_path(#page) %>
*Note that I am very new to programming and rails in general. This is probably really simple.
In general it's a bad idea to link to a "show" action without having an object to show. This is what the "index" action is for.
Try linking to it like this:
<%= link_to 'Practice', pages_path %>
Then in your controller do this:
def index
page = Page.where(knowledge: 'Learning').first
redirect page_path(page)
end
That way you'll always have an ID when the show action is called. I think you'll also want to adjust your show method to this so that #page and #next are available to your view.
def show
#page = Page.find_by(id: params[:id])
#next = Page.where("id > ?", params[:id]).order(:id).first
end
Welcome to Rails!
The page path requires an id. If you go into your project folder, and type rake routes, it will show you a list of your routes, and which require ids. Like this:
user GET /users/:id(.:format) users#show
You are going to need to get the first record and load it in your index page:
def index
#page = Page.where(knowledge: 'Learning').first
end
Then for your link on your index page:
<%= link_to 'Practice', page_path(#page, first: true) %>
first: true is a second parameter that you can check for in your show action so you can tell if the person is coming from the index page.
Then for your show action - (params always returns a string, that's why, the 'true' is in quotes for your show action)
def show
if params[:first] == 'true'
#page = Page.where(knowledge: 'Learning').first
#next = Page.where("id > ?", #page.id).order(:id).first
else
#page = Page.where("id > ?", params[:id]).order(:id).first
#next = Page.where("id > ?", #page.id).order(:id).first
end
end
For your view:
<% if #page%>
<p> <%= #page.word %></p>
<p> <%= #page.content %></p>
<p><%= link_to "Next", page_path(#next) %></p>
<% else %>
<p> Good Job!</p>
<p><%= link_to "Home", pages_path %> </p>
<%end%>
You also may want to look into the will_paginate gem for pagination: https://github.com/mislav/will_paginate
My form gets passed a 'new' Quiz (not saved to the database). My form partial looks like this:
<%= form_for(#quiz) do |f| %>
<p>
<%= f.check_box(:answer1) %>
<%= f.check_box(:answer2) %>
<%= f.check_box(:answer3) %>
<%= f.check_box(:answer4) %>
<%= f.check_box(:answer5) %>
<%= f.check_box(:answer6) %>
<%= f.check_box(:answer7) %>
<%= f.check_box(:answer8) %>
</p>
<p>
<%= f.submit("Get my results!") %>
</p>
<% end %>
Here is my QuizzesController#create action:
def create
#results = Quiz.create(post_params) #from private method
if #results.save
redirect_to results_path
else
#error handle here
end
end
...which gets triggered when the user clicks 'get my results' on my quiz form. And the post_params method looks like this:
def post_params
params.require(:quiz).permit(:id, :user_id, :answer1, :answer2, :answer3, :answer4, :answer5, :answer6, :answer7, :answer8) #add other attributes here
end
My results/index.html.erb looks like this:
<div class="container">
<!-- Example row of columns -->
<div class="row">
<h1>Results</h1>
<p><%= #results.inspect %></p>
</div>
</div>
But that 'inspected' Quiz instance returns 'nil' for all the answers1, answers2 etc attributes. Any idea why that would be? Is there something I'm NOT doing to save the user's answers to the database?
The reason it shows nil is because you are not setting the variable.
After creating and saving, you redirect to results_path and the variable #results does not persist during a redirect. Without seeing the full code, I'll have to guess at your naming conventions but there are two ways to do this.
1) If you want to redirect to the index then in the code for your index action, you can set the variable:
#results = Quiz.last
This is easy to work with in development because you are the only user and this will always return the last quiz you created. Not so great in production.
2) The alternative is to redirect to the show action for that quiz.
def create
#results = Quiz.new(post_params)
if #results.save
redirect_to result_path(#results)
else
# error handle here
end
end
Again, I have had to guess that result_path is the correct path. Without seeing the full routes file, I cannot be sure but you can rename accordingly if necessary.
I have RoR 4.2.0beta. (Although it s irrelevant as this is a beginer problem).
My form does not insert in the database the "propuneres" that I am creating trough it. And as a result they do not show in the index page when I get redirected to it. They show up when I create them through the console.
class PropuneresController < ApplicationController
before_action :prop_params
def new
#user = User.find(params[:user_id])
#propunere = #user.propuneres.build
end
def create
#user= User.find(params[:user_id])
#propunere = #user.propuneres.new(params[:prop_params])
#propunere.save
if #propunere.empty?
render 'new'
else
redirect_to user_propuneres_path
end
end
def index
#user = User.find(params[:user_id])
#propunere = #user.propuneres(params[:prop_params])
end
private
def prop_params
params.require(:propunere).permit(:titlu, :body)
end
end
new.html.erb
<h2> Propunere Nouă </h2>
<%= form_for #propunere do |f| %>
<ul>
<% #propunere.errors.full_messages.each do |error| %>
<li><%= error %></li>
<% end %>
</ul>
<p>
<%= f.label :titlu %><br />
<%= f.text_field :titlu %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
index.html.erb
<h2> Propuneri: </h2>
<% #propunere.each do |p| %>
<%= p.titlu %>
<%= p.body %>
<% end %>
Not sure if its relevant, but you have code
#propunere.save
if #propunere.empty?
render 'new'
else
redirect_to user_propuneres_path
end
Object #prorunere will never be empty, since you have
#propunere = #user.propuneres.new, which assigneds user_id to your #propunere object and
render 'new' will never be rendered, therefore you wont see any validation errors and never find out why your record wasnt created
Also since you have that piece of code, and dont see errors, this is what most like broke your code
#user.propuneres.new(params[:prop_params]) - you should use your permitted params, so it'd look like
#propunere = #user.propuneres.new(prop_params)
I've cloned your repo, here's the problem: in new.html.erb you had
<%= form_for #propunere, url: new_user_propunere_path(#user, #propunere), html: { method: :get } do |f| %>
Both the url and the method are wrong. user_propuneres_path will give you the correct url for the create action and the correct method is :post, not :get. This is why you never reached the create action.
You also need to change from #propunere = #user.propuneres.new(params[:propunere]) to #propunere = #user.propuneres.new(prop_params), otherwise you'll get a ActiveModel::ForbiddenAttributesError exception.
You can see all the routes in the app by running rake routes in the terminal.
I don't think you need the params in your index action:
#propunere = #user.propuneres
and it would be more logical to write it in plural since you have many of them.
Edit:
As Avdept suggested your create action should look like this:
def create
#user = User.find(params[:user_id])
#propunere = #user.propuneres.new(prop_params)
respond_to do |format|
if #propunere.save
format.html { redirect_to user_propuneres_path(#user), notice: 'Your propunere has been saved' }
else
format.html { render :new }
end
end
end
Do you have any validations for the Propunere model? Maybe the model is invalid. You can use
the create! method instead of create for testing, because it will throw an exception if the object cannot be saved. Also try puts #propunere.inspect before persisting it and check that the contents of the object are ok, the output will be shown in the development log.