This is my first question so I hope I can be as specific as possible, but don't be harsh.
I'm going through Agile Web Development with Rails and am very new to programming.
I want to hide a 'Checkout' button while I am on the order/new page so that it can't do anything nasty to the users purchase.
At the moment, I don't really understand how instance variables work, since it seems like no matter where I declare my instance variable, in a view or in orderscontroller#new, it always validates to true.
This seems to be the case because when I use the instance variable in the view to hide a div ( with hidden_div_if(condition == true) ) the buttons ALWAYS get hidden!
Not only that, but when I do:
<%= hidden_div_if( #hide_checkout_button == false ) do %>
<td><%= button_to 'Empty cart', cart, :method => :delete,
:confirm => 'Are you sure?' %></td>
<% end %>
<%= hidden_div_if( #hide_checkout_button == true ) do %>
<td><%= button_to "Checkout", new_order_path, :method => :get %></td>
<% end %>
BOTH buttons get hidden! How can that be!?!
In this example, I have placed the variable declaration in views\orders_form.html.erb:
<%= #hide_checkout_button = true %>
<%= form_for(#order) do |f| %>
<% if #order.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#order.errors.count, "error") %>
prohibited this order from being saved:</h2>
<ul>
<% #order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
...
Here is a discussion-forum with solutions for this problem, but they don't work for me and I don't know why: http://pragprog.com/wikis/wiki/Pt-G-2/version/35
And here is the question itself:
What happens if you click the Checkout button in the sidebar while the
checkout screen is already displayed? Can you find a way to disable
the button in this circumstance? (Hint: variables set in the controller
are available in layouts and partials as well as in the directly rendered
template.)
If you need any more information to help please ask, I'm not quite sure how much detail to provide or what information is important.
Thanks in advance :-)
def new
#cart = current_cart
if #cart.line_items.empty?
redirect_to store_url, :notice => "Your cart is empty"
return
end
puts 34
#hide_checkout_button = true
#order = Order.new
puts 37
respond_to do |format|
format.html # new.html.erb
format.json { render json: #order }
end
end
Started GET "/assets/logo.png" for 127.0.0.1 at 2012-11-13 20:33:40 +0000
Served asset /logo.png - 304 Not Modified (1ms)
[2012-11-13 20:33:40] WARN Could not determine content-length of response body.
Set content-length of the response or set Response#chunked = true
*
34
37
*
/orders/new
Started GET "/orders/new" for 127.0.0.1 at 2012-11-13 20:33:49 +0000
Processing by OrdersController#new as HTML
←[1m←[36mCart Load (1.0ms)←[0m ←[1mSELECT "carts".* FROM "carts" WHERE "carts
"."id" = ? LIMIT 1←[0m [["id", 63]]
←[1m←[35m (1.0ms)←[0m SELECT COUNT(*) FROM "line_items" WHERE "line_items"."c
art_id" = 63
The problem is a missing =. do <%= %> instead.
<%= hidden_div_if( #hide_checkout_button == true ) do %>
<td><%= button_to "Checkout", new_order_path, :method => :get %></td>
<% end %>
Also, for boolean checks you can just do if(boolean) which will evaluate the same as if you put == true/false
<%= hidden_div_if( #hide_checkout_button) do %>
#...
<% end %>
You want to set that variable on the method that calls the view. In this case it is the new method in OrdersController
def new
#hide_checkout_button = true
end
Edit:
add this to the hidden div just to see if it helps finding the element to set the attribute to
<%= hidden_div_if(#hide_checkout_button, id: 'cart') do %>
with (in the application helper)
def hidden_div_if(condition, attributes = {}, &block
if condition
attributes["style"] = "display: none"
end
content_tag("div", attributes, &block)
end
if that doesn't do it, then just do it this way
<% if #hide_checkout_button %>
<td><%= button_to "Checkout", new_order_path, :method => :get %></td>
<% else %>
<td><%= button_to 'Empty cart', cart, :method => :delete, :confirm => 'Are you sure?' %></td>
<% end %>
used
<div class="actions">
<% if not #hide_checkout_button %>
<%= button_to 'Checkout', new_order_path, method: :get, class: "checkout" %>
<% end %>
<%= button_to 'Empty cart', cart, method: :delete, data: { confirm: "Are you sure?" }, remote: true %>
Related
def edit
#exercise = Exercise.find(params[:exercise_id])
#play = #exercise.plays.find(params[:id])
end
def update
#exercise = Exercise.find(params[:exercise_id])
#play = #exercise.plays.find(params[:id])
if #exercise.plays.update_attributes(play_params)
redirect_to #exercise_path
else
render action: :edit
end
end
partial view that is being rendered to show all created plays has
<p><%= play.name %></p>
<p><%= play.sets %></p>
<p><%= play.reps %></p>
<%= link_to "edit", edit_exercise_play_path( #exercise, play) %>
that is plays_controller :edit, :update method, Actually i have two classes, one is ExerciseController and other one is PlaysController, ExerciseController has_many plays, i am rendering two partials one to create play and other one to show that play on same page on the partial which is rendering the play after creation, but now i want to add edit feature with edit_exercise_play_path,
<%= link_to "Edit", edit_exercise_play_path(#play) %>
after this i am facing unmatched constraint error.Thanks
resources :exercises do
resources :plays
end
Show.html.erb from ExercisesController
<h2>Your Workout Details </h2>
<p><%= #exercise.workout %></p>
<p><%= #exercise.mode %></p>
<p><%= #exercise.date.strftime("on %A at %H:%M Dated as %d %B") %></p>
<p><%= #exercise.length %></p><br />
<h3> Games you Played </h3>
<%= render #exercise.plays %>
<h3>Add new Game </h3>
<%= render 'plays/form' %>
<%= link_to "Edit", edit_exercise_path %> | |
<%= link_to "Destroy", exercise_path(#exercise), :confirm => "Are you
sure?", :method => :delete %> | |
<%= link_to "Back", root_path %>
" Logs "
Started GET "/exercises/5" for 127.0.0.1 at 2018-09-25 18:12:21 +0500
Processing by ExercisesController#show as HTML
Parameters: {"id"=>"5"}
Exercise Load (0.0ms) SELECT "exercises".* FROM "exercises" WHERE "exercises"."id" = ? LIMIT ? [["id", 5], ["LIMIT", 1]]
Rendering exercises/show.html.erb
Play Load (0.0ms) SELECT "plays".* FROM "plays" WHERE "plays"."exercise_id" = ? [["exercise_id", 5]]
Rendered collection of plays/_play.html.erb [6 times] (14.0ms)
Rendered exercises/show.html.erb (39.7ms)
Completed 500 Internal Server Error in 136ms (ActiveRecord: 0.0ms)
As per your routes, the path helper edit_exercise_play_path also require value for :exercise_id key. But you haven't passing any. Changing the link_to to below should fix your problem
<%= link_to "Edit", edit_exercise_play_path(#exercise, #play) %>
Update:
As per our discussion over the chat, the link_to edit should look like below
<%= link_to "Edit", edit_exercise_play_path(#exercise, play) %>
as you are rendering a partial with <%= render #exercise.plays %> which creates a play variable.
undefined method `model_name' for nil:NilClass
For this, you should change <%= render 'form' %> to <%= render 'form' , exercise: #exercise, play: #play %> and in the _form.html.erb change the first line of the form to <%= simple_form_for ([exercise, play]) do |f| %>
undefined method `update_attributes' for
Play::ActiveRecord_Associations_CollectionProxy:0x0000000f69c710
The reason for this error is in your update method you have have #exercise.plays.update_attributes(play_params). This means you are calling update_attributes on collection. You should change
if #exercise.plays.update_attributes(play_params)
to
if #play.update_attributes(play_params)
In a Rails 3 project, I have an index list of costprojects.
I have a controller action called `viewprojects'.
I would like to add a checkbox column to the index list. Then let the user select which projects should be included in the pdf.
index:
<% #costprojects.each do |costproject| %>
<tr>
<td><%= check_box_tag "costproject_ids[]", costproject.id %></td>
...
<%= link_to 'PDF Selected', costprojects_viewprojects_path(:format => "pdf",:costproject_ids => costproject_ids[] ), :class => 'btn btn-success', :target => "_blank" %>
Controller:
def viewprojects
#costprojects = params[:costproject_ids]
respond_to do |format|
format.html
format.pdf do
render :pdf => "costprojects.pdf",
:show_as_html => params[:debug].present?,
:page_size => 'letter'
end
end
end
I'm getting:
undefined local variable or method `costproject_ids'
Update1:
Tried:
def viewprojects
#costprojects = params[:costproject_ids[]]
...
<%= link_to 'PDF Selected', costprojects_viewprojects_path(:format => "pdf",:costproject_ids[] => costproject_ids[] ), :class => 'btn btn-success', :target => "_blank" %>
I get "wrong number of arguments (0 for 1..2)"
Do I need to add form_tag and submit_tag?
Thanks for the help!
As Legendary mentioned in the comments you need to wrap this in a form. A link_to isn't going to transmit the value of the selected ids unless its contained in its query parameters, which it can't know at render time.
Try something more like this:
<%= form_tag costprojects_viewprojects_path(format: "pdf") do %>
<% #costprojects.each do |costproject| %>
<tr>
<td><%= check_box_tag "costproject_ids[]", costproject.id %>
</td>
<% end %>
...
<%= submit_tag "PDF Selected", class: "btn btn-success" %>
<% end %>
You should then be able to access the array of cost_project_ids simply with params[:cost_project_ids] in the controller, which it seems you're already doing. Note that this will send an HTTP POST, rather than a GET, so ensure your routes are correctly setup for that verb.
I have a helper method that has the following bit of code. It's part of an AJAX cart that's displayed on multiple pages on the site
module CartsHelper
def switch_buttons
unless URI(request.referer).path==new_order_path && !current_page?(store_path) \
|| current_page?(new_order_path)
#checkout = true
else
#checkout = false
end
end
end
Here's the cart partial view
<h2> Your Cart</h2>
<table>
<%= render(cart.line_items)%>
<tr class ="total_line">
<td colspan="2">Total</td>
<td class="total_cell"><%= number_to_currency(cart.total_price)%></td>
</tr>
</table>
<% if switch_buttons %>
<%= button_to 'Checkout', new_order_path, method: :get %>
<%= button_to 'Empty cart', cart, method: :delete,
confirm: 'Are you sure?', remote: true %>
<% else %>
<%= button_to 'Cancel Order', store_path, method: :get %>
<% end %>
The URI(request.referer).path is giving a bad argument (expected URI object or URI string) error in all of my tests. It works in the actual browser. I'm guessing it's because the tests don't actual go through the urls so request.referer is nil? Is there some way to set up the test to be able to get through this code?
Two things:
First, this answers your main question:
How do I set HTTP_REFERER when testing in Rails?
Second, it's not a given that request.referer will be set. Most browsers supply the header when you navigate from a previous page; most don't when you hand-enter a URL. HTTP clients can't be assumed to do so overall, and you have to be prepared to get nil from that attribute.
I noticed that when I create a record in one of my tables, and I have some kind of data that is associated with that table, it adds 1 record already, but it is nil?
For instance:
lists controller
def show
#list = List.find(params[:id])
#idea = #list.ideas.build
respond_to do |format|
format.html # show.html.erb
format.json { render json: #list }
end
end
list model
has_many :ideas
idea model
belongs_to :list
list > show.html.erb
<%= #list.ideas.each do |idea| %>
<div>
<div class="list_idea_desc"><%= idea.description %></div>
<div><%= link_to 'Show', idea %></div>
<div><%= link_to 'Destroy', idea, method: :delete, data: { confirm: 'Are you sure?' } %> </div>
</div>
<% end %>
I get this record:
[#<Idea id: nil, name: nil, description: nil,
picture: nil, created_at: nil, updated_at: nil, list_id: 1>]
This idea record automatically gets inserted into my database when I create a new list. Why does this happen?
Difference between new and build is that build adds the newly created object to the collection:
Replace:
#idea = #list.ideas.build
With:
#idea = #list.ideas.new
Or if you want to use build only, you should
Replace:
<%= #list.ideas.each do |idea| %>
With:
<%= #list.ideas(true).each do |idea| %>
true discards the cached copy of ideas and goes back to the database.
This is due to #idea = #list.ideas.build code line, remove it and check it.
It may works for your view.
<% #idea = #list.ideas.build %>
<%= form_for [#list,#idea] do |f| %>
Try this:
<%= #list.ideas.each do |idea| %>
<% if idea.present? %>
<div>
<div class="list_idea_desc"><%= idea.description %></div>
<div><%= link_to 'Show', idea %></div>
<div><%= link_to 'Destroy', idea, method: :delete, data: { confirm: 'Are you sure?' } %> </div>
</div>
<% end %>
<% end %>
Use present? condition in record saving time also.
I have a nav menu with 2 tabs/links in the show.html.erb file, in UsersController.rb, I would like to use ajax to render different partial for the tabs.
In the show.html.erb I have a div named profile-data where I want to show the content.
So I do something like this:
The link structure:
<li><%= link_to "College friends", college_friends_path, :remote => true %></li>
<li><%= link_to "Highschool friends", highschool_friends_path, :remote => true %></li>
I define the routes:
match "college_friends" => "users#college_friends", :as => "college_friends"
match "highschool_friends" => "users#highschool_friends, :as => "highschool_friends"
And I define in my UserController.rb the necessary methods:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def college_friends
respond_to do |format|
format.js
end
end
def highschool_friends
respond_to do |format|
format.js
end
end
end
Last thing we have the JS files:
*college_friends.js.erb*
$('#profile-data').html("<%= escape_javascript(render(:partial => 'college_friends')) %>");
*highschool_friends.js.erb*
$('#profile-data').html("<%= escape_javascript(render(:partial => 'highschool_friends')) %>");
The partial code: _college_friends.html.erb
<% groups = #user.friends.group_by(&:college_name) %>
<% sorted_groups = groups.sort_by{|key, values| values.count}.reverse %>
<% sorted_groups.each do |collegename, friends| %>
<% next if collegename.blank? %>
<div class="contentbox">
<div class="box-header">
<h3><%= collegename %></h3>
<div class="meta-info">
<p><i class="icon-map-marker"></i> Malmö</p>
<p><i class="icon-user"></i><span class="count"> <%= friends.count %></span> vänner</p>
</div>
</div>
<ul class="friends-list">
<% friends.map do |friend| %>
<li><%= image_tag(friend.image) %>
<% end %>
</ul>
</div>
<% end %>
Nothing happens when I click the the links, and get this error in the console:
Started GET "/universitet_friends" for 127.0.0.1 at 2012-07-29 01:53:39 +0200
Processing by UsersController#universitet_friends as JS
Rendered users/_universitet_friends.html.erb (1.6ms)
Rendered users/universitet_friends.js.erb (3.1ms)
Completed 500 Internal Server Error in 7ms
ActionView::Template::Error (undefined method `friends' for nil:NilClass):
1: <% groups = #user.friends.group_by(&:college_name) %>
2: <% sorted_groups = groups.sort_by{|key, values| values.count}.reverse %>
3: <% sorted_groups.each do |collegename, friends| %>
4: <% next if collegename.blank? %>
app/views/users/_universitet_friends.html.erb:1:in `_app_views_users__universitet_friends_html_erb___1983680250475155079_70236040373720'
app/views/users/universitet_friends.js.erb:1:in `_app_views_users_universitet_friends_js_erb__1317362850668628869_70236044930260'
app/controllers/users_controller.rb:19:in `universitet_friends
Any help would be appreciated.
ActionView::Template::Error (undefined method `friends' for
nil:NilClass):
This is telling you that your #user variable is nil. This happened because when you went back to your controller for the AJAX request, you never actually set the #user variable. It does not persist between requests. You need to pass that variable during the ajax request. One way to do it is to add a user_id param to the ajax URL.
May be you can do something like this too
<%=link_to "Highschool friends", college_friends_path(:user_id => #user.id), :remote => true %>
The best way to do however would be to pass the user_id param to ajax url..you can fire the ajax request on link "on-click" event.