I try to assign to result of rendering an action to an element on page. That should be an easy task but the following statement:
$(".box:first").after("<%= escape_javascript(render :action => "new" ) %>");
will result in the following error message:
ActionView::Template::Error (undefined method `formats' for nil:NilClass):
1: $(".box:first").after("<%= escape_javascript(render(:action => "new") ) %>");
The same code works if i try to render a partial using :partial => "new" (given that the partial with the given name exists)
The error message will be the same if I change ':action' f.e. to ':foobar'.
Any ideas what i am doing wrong or is this simple a bug in rails? (3.0.7)
It is a bug in your application. Actually it is a bug in your new action in controller
Result of rendering of an action? That's probably not the very best idea. As you said, the code works when you use partial, and that's what you should use.
This is from official Rails guides:
Using render with :action is a
frequent source of confusion for Rails
newcomers. The specified action is
used to determine which view to
render, but Rails does not run any of
the code for that action in the
controller. Any instance variables
that you require in the view must be
set up in the current action before
calling render.
http://guides.rubyonrails.org/layouts_and_rendering.html#using-render
Related
Im trying to set up a (basic) test for a new feature I am going to implement. I have a job controller and instead of default showing all jobs I like to hide all the ones which is archived. I tried different ways but it seems like i am missing a piece or two of this puzzle. First i tried with calling 'visit' but get the message it does not exist. Second approach is using 'render' but that also ends up in a error saying render does not exists. (can i even use these methods in a controller spec?)
Is it wrong to put this in a controller test?
2 last test are causing errors
require "rails_helper"
require "spec_helper"
describe JobsController, :type => :controller do
context 'GET index' do
it "should be successful" do
get :index
expect(response).to be_success
end
it "renders the index template" do
get :index
expect(response).to render_template("index")
end
it "should not show any archived jobs as default" do
visit jobs_path
page.should have_no_content("Archived")
end
it 'should show the headers' do
render :template => 'job/index', :layout => 'layouts/job'
rendered.should_not contain('Archived')
end
end
end
Capybara is used for feature specs, and its matchers can be used in view specs.
Controller specs, by default, don't actually render the view because they're the wrong place to be checking for page content - https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs
You should probably move some of your tests to feature tests/view tests
Route defined as follows
resources :purchases do
collection do
put :wirecardtest
end
end
Controller actions redirect in one of the following manners with associated error generated
format.html { redirect_to wirecardtest_purchase_path(#purchase)
undefined method `wirecardtest_purchase_path'
format.html { redirect_to wirecardtest_purchases_path(#purchase)
/purchases/wirecardtest.44
Behaviour is identical when putting code in view.
The ressource is defined in plural mode, as it ought to be. The redirect, as it is supposed to call a specific ressource should call the singular model-action mode (in plural it would generate the period).
I don't understand how I got into this damned-if-you-do, damned-if-you-don't position.
wirecardtest_purchases PUT /purchases/wirecardtest(.:format) purchases#wirecardtest
That's your mistake right there.. the path is generated as 'wirecardtest_purchases' but you are using 'wirecardtest_purchase' note the missing 's' to pluralize the 'purchase'.
Remember its a collection. So the path method is pluralized by rails.
When in doubt rake routes :)
---Update---
Improving the answer (check comments). Need here is to actually define a route as :member and not a :collection if you want to act upon a single object. Referring to Rails Docs,
resources ::purchases do
member do
get 'wirecardtest'
end
end
I have an app where I'm creating a get action called "new_911". When I put new_911_call_path in the application layout I get an error "no route matches new_911 controller: calls". Yet there is an action in the calls controller called new_911. What am I doing wrong?
Calls Controller:
def new_911
#call = Call.new :call_status => "open"
respond_with #call
end
application.html.erb
<li><%= link_to 'New 911 Call', new_911_call_path %></li>
routes.rb
resources :calls do
member do
post 'close'
post 'cancel'
post 'note'
get 'new_return'
get 'duplicate_call'
get 'edit_times'
put 'update_billing'
get 'new_911'
end
rake routes:
new_911_call GET /calls/:id/new_911(.:format) calls#new_911
You need to add the parameter to the route. You're using a member route so you need to add the id parameter, take a look of this. You may need to change that route.
Figured it out. I was using a member instead of a collection. Also using new_911 gave me a constant error so I changed it to EmergencyCalls for my controller schema and utilized the normal "new" action. Added resources :emergency_calls to my routes file and it worked.
Sorry for the goof.
I have made a resource.
resources :dashboards
I have a partial file which contains a form and I want to use this partial (as the form elements won't change) to update and create. So here is what I have:
Controller
class DashboardsController < ApplicationController
def new
#dashboard = Dashboard.new
end
end
View
/dashboards/new.html.erb
<%= render :partial => "form", :locals => { :dashboard => #dashboard } %>
Partial Form
/dashboards/_form.html.erb
<%= form_for(#dashboard) do |form| %>
.....
<% end %>
Ruby Guide
The Ruby Guide states:
The Article model is directly available to users of the application, so — following the best practices for developing with Rails — you should declare it a resource. When dealing with RESTful resources, calls to form_for can get significantly easier if you rely on record identification. In short, you can just pass the model instance and have Rails figure out model name and the rest. For example:
## Creating a new article
# long-style:
form_for(#article, :url => articles_path)
# same thing, short-style (record identification gets used):
form_for(#article)
## Editing an existing article
# long-style:
form_for(#article, :url => article_path(#article), :html => { :method => "put" })
# short-style:
form_for(#article)
Result
I thought I have followed the Rails Guide correctly. Because I made #dashboard a resource. I could just pass it into the form and have it handle the action, method and the rest. Instead I'm getting this:
<form accept-charset="UTF-8" action="/dashboards" class="new_dashboard" id="new_dashboard_" method="post">
According to the docs. Shouldn't the action of my form now be "/dashboards/new" because we are on the new action? And should it be passing an extra field declaring the method to be put when I use the same code in the /edit action??
My result is always the same no matter what. The form never changes.
What am I doing wrong?
EDIT
Here is my router info from rake routes
GET /dashboards(.:format) dashboards#index
POST /dashboards(.:format) dashboards#create
GET /dashboards/new(.:format) dashboards#new
GET /dashboards/:id/edit(.:format) dashboards#edit
GET /dashboards/:id(.:format) dashboards#show
PUT /dashboards/:id(.:format) dashboards#update
DELETE /dashboards/:id(.:format) dashboards#destroy
You are correct that you should be able to "pass #dashboard into the form and have it handle the action, method and the rest." The issue here is what new is in the context of RESTful actions.
When you declare a set of resources with resources :dashboards, you are creating a set of routes which map requests to controller actions:
GET /dashboards index
GET /dashboards/new new
POST /dashboards create
GET /dashboards/:id show
GET /dashboards/:id/edit edit
PUT /dashboards/:id update
DELETE /dashboards/:id destroy
You can check this if you run rake routes.
The issue here is that the new action is defined as a GET request to the path /dashboards/new, i.e. this is the route for the form itself. The URL in the action attribute of the actual form is something else: this is where the form will post the data to with a POST request, which on the server (rails) side will map to the create controller action.
When you use the form helper with form_for(dashboard), a form is created with a route corresponding to what dashboard is: if it is a new record (i.e. it does not yet exist in the database), then the form action will be create (and point to /dashboards), whereas if it already exists it will point to the actual URL for the record (e.g. /dashboards/123). This is what makes the form helpers so useful.
So, to sum up, /dashboards is the correct URL, not for the new action but for the create action, which the form helper uses because dashboard is a new record. new is the route to the page where the form resides, i.e. /dashboards/new.
Hope that makes sense.
p.s. as a side note, you shouldn't be accessing #dashboard in the partial if you are passing it in as a local (:locals => { :dashboard => #dashboard }). Just use dashboard.
I'm running Rails 3.1.1, RSpec 2.7.0 and HAML 3.1.3.
Say I have the following view files:
app/views/layouts/application.html.haml
!!!
%html
%head
%title Test
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
%body
= content_for?(:content) ? yield(:content) : yield
app/views/layouts/companies.html.haml
- content_for :content do
#main
= yield :main
#sidebar
= yield :sidebar
= render :template => 'layouts/application'
app/views/companies/index.html.haml
- content_for :main do
%h1 MainHeader
- content_for :sidebar do
%h1 SidebarHeader
And the following spec file:
spec/views/companies/index_spec.rb
require 'spec_helper'
describe 'companies/index.html.haml' do
it 'should show the headers' do
render
rendered.should contain('MainHeader')
rendered.should contain('SidebarHeader')
end
end
When I run RSpec, I get the following error:
1) companies/index.html.haml should show the headers
Failure/Error: rendered.should contain('MainHeader')
expected the following element's content to include "MainHeader":
# ./spec/views/companies/index_spec.rb:7:in `block (2 levels) in <top (required)>'
At first, I thought RSpec was somehow missing the content_for blocks when rendering the view files. However, I was not able to find any issue related to it on RSpec's github repository, so I'm not sure who's to blame here.
One (recent) solution I found is at http://www.dixis.com/?p=571. However, when I try the suggested code
view.instance_variable_get(:#_content_for)
it returns nil.
Is there a way to test content_for in view specs?
Is there a better way to structure my layout files, such that I'm actually able to test them and still achieve the same end result?
Using Rspec 2 with Rails 3, in order to write view specs for usage of content_for, do this:
view.content_for(:main).should contain('MainHeader')
# instead of contain() I'd recommend using have_tag (webrat)
# or have_selector (capybara)
p.s. the value of a content_for(...) block by default is an empty string, so if you want to
write specs showing cases in which content_for(:main) does not get called, use:
view.content_for(:main).should be_blank
Your spec could be written as:
it "should show the headers" do
render
view.content_for(:main).should contain('MainHeader')
view.content_for(:side_header).should contain('SidebarHeader')
end
This way your spec shows exactly what your view does, independent of any layout. For a view spec, I think it's appropriate to test it in isolation. Is it always useful to write view specs? That's an open question.
Instead if you want to write specs showing what the markup served to the user looks like, then you'll want either a request spec or a cucumber feature. A third option would be a controller spec that includes views.
p.s. if you needed to spec a view that outputs some markup directly and delegates other markup to content_for(), you could do that this way:
it "should output 'foo' directly, not as a content_for(:other) block" do
render
rendered.should contain('foo')
view.content_for(:other).should_not contain('foo')
end
it "should pass 'bar' to content_for(:other), and not output 'bar' directly" do
render
rendered.should_not contain('bar')
view.content_for(:other).should contain('bar')
end
That would probably be redundant, but I just wanted to show how render() populates rendered and view.content_for. "rendered" contains whatever output the view produces directly. "view.content_for()" looks up whatever content the view delegated via content_for().
From the RSpec docs:
To provide a layout for the render, you'll need to specify both the template and the layout explicitly.
I updated the spec and it passed:
require 'spec_helper'
describe 'companies/index.html.haml' do
it 'should show the headers' do
render :template => 'companies/index', :layout => 'layouts/companies'
rendered.should contain('MainHeader')
rendered.should contain('SidebarHeader')
end
end
Do not bother with view specs. They're hard to write well, and they don't test enough of the stack to be worth using (especially in view of the difficulty writing). Instead, use Cucumber, and test your views in the course of that.
You generally don't want to test content_for specifically either: that's implementation, and you should instead be testing behavior. So just write your Cucumber stories so they test for the desired content.
If for some odd reason you do need to test content_for, RSpec has a syntax that's something like body[:content_name] or body.capture :content_name depending on the version (or something like that; haven't used it in a while). But consider carefully whether there's a better way to test what you actually want to test.