Why am I getting "no route matches [POST]" in my nested resources? - ruby-on-rails-3

I have a project that contains projects that have todos that have tasks. When I try to create a new task, I get this error when I submit:
No route matches [POST] "/projects/1/todos/19/tasks/new"
Here is my form:
<%= form_for [#todo, #todo.tasks.new], :url => new_project_todo_task_path(#project, #todo) do |f| %>
<div class="field">
<%= f.label :description, "Description" %><br />
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %> or <%= link_to "Cancel", "#", :id => "cancel_new_task_link" %>
</div>
<% end %>
Here is my controller:
class TasksController < ApplicationController
before_filter :authenticated?
before_filter :get_project_and_todo
respond_to :html, :xml, :json, :js
def new
#task = #todo.tasks.new
end
def create
#task = #todo.tasks.new(params[:task])
if #task.save
respond_with #todo, :location => project_todo_path(#project, #todo)
else
render "new"
end
end
private
def get_project_and_todo
#project = Project.find(params[:project_id])
#todo = #project.todos.find(params[:todo_id])
end
end
Here are my routes:
resources :projects do
resources :todos do
resources :tasks
end
end
Thanks

Your URL should not be new_project_todo_task_path(#project, #todo). You don't need to specify the URL here as Rails will imply it from the parameters passed in to form_for.
If the final object is a new object and not persisted in the database then it will make a POST request to, in this case, /projects/:project_id/todos. You're declaring in your example that you want to make a POST request to /projects/:project_id/todos/new, for which there is no POST route and that is why it's failing.

Related

Rails Undefined Method 'model_name'

I have the following model:
class Contact
attr_accessor :name, :emails, :message
def initialize(attrs = {})
attrs.each do |k, v|
self.send "#{k}=", v
end
end
def persisted?
false
end
end
I am calling to a contact form in my view like so:
<div class="email_form">
<%= render 'form' %>
</div>
Here is the controller:
class ShareController < ApplicationController
layout "marketing_2013"
respond_to :html, :js
def index
#contact = Contact.new
end
end
Here is the Form:
<%= form_for(#contact) do |f| %>
<%= f.label :name, "Your Name" %>
<%= f.text_field :name %>
<%= f.label :text, "Send to (separate emails with a comma)" %>
<%= f.text_field :emails %>
<%= f.label :message, "Email Text" %>
<%= f.text_area :message %>
<%= f.submit %>
<% end %>
For some reason I keep getting this error:
undefined method model_name for Contact:Class
Any reason why what I have currently wouldn't work?
Besides the correct route in your config/routes.rb, you will also need these two instructions on your model:
include ActiveModel::Conversion
extend ActiveModel::Naming
Take a look at this question: form_for without ActiveRecord, form action not updating.
For the route part of these answer, you could add this to your config/routes.rb:
resources :contacts, only: 'create'
This will generate de following route:
contacts POST /contacts(.:format) contacts#create
Then you can use this action (contacts#create) to handle the form submission.
add include ActiveModel::Model to your Contact file
your route probably doesn't go where you think it's going and therefore #contact is probably nill
run "rake routes" and check the new path.. if you are using defaults, the route is
new_contact_path.. and the erb should be in file: app/views/contacts/new.html.erb
def new
#contact = Contact.new
end

Create a new perfil inside a persons _controller

I'm in rails 3.2.2
I'm trying to create a new perfil inside a persons_controller
Models symplify:
class Person < ActiveRecord::Base
belongs_to :perfil, :foreign_key=>'perfil_id'
class Perfil < ActiveRecord::Base
has_one :person
I created ad_perfil inside persons_controller
def ad_perfil
#person = Person.find(params[:id])
#perfil = Perfil.new
end
and I supused 2 ways:
1) using f.submit
ad_perfil.html.erb:
<%= #person.nombre %>
<%= form_for(#perfil) do |f| %>
<div class="field">
<%= f.label :nombre %><br />
<%= f.text_field :nombre %>
</div>
<%= f.submit %>
<% end %>
this redirect me to create to perfils_controller and there I can't get #persona:
def create
#perfil = Perfil.new(params[:perfil])
#person = Person.find(params[:id])
respond_to do |format|
if #perfil.save
format.html { redirect_to #perfil, notice: 'Perfil was successfully created.' }
format.json { render json: #perfil, status: :created, location: #perfil }
#person.perfil_id = #perfil.id
#person.save
2) I created a new def in persons_controller:
def new_perf
#perfil = Perfil.new(params[:perfil])
#person = Person.find(params[:id])
if #perfil.save
#person.perfil = #perfil
#person.update_attributes(params[:person])
redirect_to #person
end
end
and I tryed change f.submit for:
<td><%= link_to 'New Perfil', :action => "new_perf", :id=> #person.id %></td>
and it created a new perfil without any field and of course don save perfil.id inside #person.perfil_id.
Is possible that I'm trying? Is there any other methods? I guess that will be more easy puting perfil.person_id instead person.perfil_id but I want access to person.perfil later.
I hope you understand me, and maybe I don't understand "submit" very well. any suggestions? thanks!

No Method Error for "comments", can't find and correct the nil value to make the comment post

I'm relatively new to rails and am trying to pull off my first polymorphic association with comments.
I am running rails 3.2.3
Edit - When I try to post a comment, my log is returning this error:
Started POST "/comments" for 127.0.0.1 at 2012-05-20 13:17:38 -0700
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"SOLcF71+WpfNLtpBFpz2qOZVaqcVCHL2AVZWwM2w0C4=", "comment"=>{"text"=>"Test this comment"}, "commit"=>"Create Comment"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 101 LIMIT 1
Completed 500 Internal Server Error in 126ms
NoMethodError (undefined method `Comment' for nil:NilClass):
app/controllers/comments_controller.rb:13:in `create'
I have tried out many different solutions offered on SO and elsewhere, including the answer from Jordan below, due, I'm sure, to my own inexperience, but have been unable to resolve the error.
The trace calls out line 13 in the Comments Controller and I commented after that line below to mark the error:
class CommentsController < ApplicationController
def index
#commentable = find_commentable
#comments = #commentable.comments
end
def new
#post = Post.find(params[:post_id])
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment]) #<<<<LINE 13
if #comment.save
flash[:notice] = "Successfully created comment."
redirect_to :id => nil
else
render :action => 'new'
end
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Posts Controller:
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #post }
end
end
Comment template (in post show)
<ul id="comments">
<% if #comments %>
<h2>Comments</h2>
<% #comments.each do |comment| %>
<li><%= comment.text %></li>
<% end %>
<% else %>
<h2>Comment:</h2>
<% end %>
</ul>
<%= simple_form_for [#commentable,Comment.new], :html => { :class => 'form-horizontal', :multipart => true } do |f| %>
<fieldset>
<%= f.input :text %>
Upload Photo <%= f.file_field :photo %>
</fieldset>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
</div>
<% end %>
Post show:
<p id="notice"><%= notice %></p>
<div class="row">
<div class="span2 offset1">
<%= image_tag #post.photo.url(:show) %>
</div>
<div class="span5">
<h1><%= #post.title %></h1>
<p><%= #post.index_text.html_safe %></p>
<p><%= #post.show_text.html_safe %></p>
<%= render "comments/comment" %>
<%= render "comments/form" %>
<% if can? :update, #course %>
<%= link_to 'Edit Post', edit_post_path(#post), :class => 'btn btn-mini' %>
<%= link_to 'Delete Post', #post,
confirm: 'Are you sure?',
method: :delete,
:class => 'btn btn-mini' %>
<%= link_to 'New Post', new_post_path, :class => 'btn btn-mini' %>
<% end %>
</div>
<nav class="span2 offset1">
<ul class="well">
<li>Category 1</li>
<li>Category 2</li>
</ul>
</nav>
</div>
<div class="row offset2">
<%= link_to 'Back to Posts', posts_path, :class => 'btn btn-mini' %>
</div>
Routes:
resources :posts, :has_many => :comments
resources :comments
It is probably something obvious that someone with more experience can resolve. Let me know if anything comes to mind. Brian
The problem is that #commentable is nil, which means that CommentsController#find_commentable is returning nil. I think your regular expression is sound, so that means one of two things is happening in find_commentable:
There aren't any keys in params that match your regex.
Your regex is matching but there aren't any records in the resulting table with the id in value.
Debug this as usual by inspecting params and the records in your database to make sure they look like you expect them to look.
The problem is your find_commentable method.
Here are the params passed to your CommentsController#create:
Started POST "/comments" for 127.0.0.1 at 2012-05-20 13:17:38 -0700
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"SOLcF71+WpfNLtpBFpz2qOZVaqcVCHL2AVZWwM2w0C4=", "comment"=>{"text"=>"Test this comment"}, "commit"=>"Create Comment"}
Here is your CommentsController#create:
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment]) #<<<<LINE 13
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
As you can see, find_commentable expects a param like xx_id (for example, comments_id) which it uses to search for an appropriate class (in case of comments_id, it will be Comment), otherwise it returns nil. Refer classify and constantize here.
Your params do not contain any such param. So, you always get a nil object.
Your find_commentable needs some rework. I think in case of nested_fields, it should be an expression like
/(.+)_attributes$/
instead of
/(.+)_id$/.
And you need to have
:accepts_nested_attributes_for :commentable
in your Comment model class.
I tried both of the above answers, but the problem continued.
I ended up consulting with a friend who suggested the following solution, which I like because it's more elegant than my original attempt and easier to read (for later, when I or someone else need to return to the code):
def find_commentable
if params[:post_id]
Post.find(params[:post_id])
#elsif params[:other_id]
# Other.find(params[:other_id])
else
# error out?
end
end
The commented out section will refer to other associations once I get them up and running.

Rails 3 - how to implement changing case of descriptions based on a check_box_tag (not part of model) in before_save callback in external class

I have an rails 3 application where there are multiple registrations (diagnosis, patient, laboratory test, service, client, user, supplier). Initially these will be populated by seeding the database. The requirement is for the description codes to be mixed case (capitalised first word) when either
1. specified by the application (some configuration setting - yet to be determined)
2. specified by data entry user
At present I have a model, view & controller for Diagnosis which contains two fields:
1. code (always to be capitalised)
2. description (First word capitalised based on check_box_tag value)
Presently I am using a before_save callback in the model to implement the conversion, but I cannot get it to only work when the check_box_tag is not selected i.e. its ignoring the check_box_tag.
I have tried changing the check_box_tag to a check_box adding an attr_assessor to the model (but not the sqlite3 db as it is not required to be stored).
This didn't work either.
How do I accomplish this? How do I override the option to use a checkbox from an internal application configuration file which results in either the checkbox being 'unavailable' or not visible if the application configuration specifies not user selectable?
Model (diagnosis.rb)
require 'DescriptionHelper'
class Diagnosis < ActiveRecord::Base
attr_accessible :code, description
string_correct_case = DescriptionHelper.new([:code, :description])
validates :code, :presence => true, :length => { :minimum => 4, :maximum => 4 }
validates :description, :presence => true
before_save string_correct_case
end
Callback in DescriptionHelper.rb
class DescriptionHelper
def initialize(attribute)
#attrs_to_manage = attribute
end
def before_save(record)
#attrs_to_manage.each do |attribute|
record.send("#{attribute}=", capitaliseWords(record.send("#{attribute}")))
end
end
private
def capitaliseWords(value)
value = value.mb_chars.downcase.to_s.gsub(/\b\w/) { |first| first.upcase }
end
end
Controller (diagnoses_controller.rb)
class DiagnosesController < ApplicationController
def new
#diagnosis = Diagnosis.new
end
def create
#diagnosis = Diagnosis.new(params[:diagnosis])
if #diagnosis.save
flash[:notice] = "Diagnosis created with params [#{#diagnosis.attributes.inspect}" #for debugging, once fixed will be just 'Diagnosis created.'
redirect_to #diagnosis
else
flash[:alert] = "Diagnosis not created."
render :action => "new"
end
end
.. other controller actions - edit, show, destroy
end
View (_form.html.erb)
<%= form_for(#daignosis) do |f| %>
<div class="field">
<%= f.label :code %>
<%= f.text_field :code %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= check_box_tag("diagnosis_desc_dont_convert", 1, false) %><%= f.label "Leave as entered" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
When this runs currently the check_box_tag is ignored.
When adding in the model an attar_assessor :description_correctcase and changing the view to use f.check_box 'description_correctcase' this is still ignored.
How does one get this to work?
Thanks in advance from a rails aspiring developer.
Finally got a solution to the problem, after reading and re-reading various SO solutions to component parts of my question. I'm not sure its correct in terms of rails, but it works.
If you can offer me a better solution I would certainly learn from this.
Here is my solution.
Model (diagnosis.rb)
require 'DescriptionHelper'
class Diagnosis < ActiveRecord::Base
attr_accessor :do_not_correctcase
attr_accessible :code, :description, :do_not_correctcase
before_save DescriptionHelper.new([:code, :description]), :if =>
lambda { |d| d.do_not_correctcase.to_s == '0' }
validates :code, :presence => true, :length => { :minimum => 4, :maximum => 4 }
validates :description, :presence => true
end
This I referenced from the following SO solution - https://stackoverflow.com/a/6388691/1108010
Controller (diagnoses_controller.rb)
class DiagnosesController < ApplicationController
def new
#diagnosis = Diagnosis.new
end
def create
#diagnosis = Diagnosis.new(params[:diagnosis])
#diagnosis.do_not_correctcase = params[:diagnosis][:do_not_correctcase]
logger.debug "New diagnoses: #{#diagnosis.attributes.inspect}"
logger.debug "Diagnosis should be valid: #{#diagnosis.valid?}"
logger.debug "code has value #{params[:code]}"
if #diagnosis.save
flash[:notice] = "Diagnosis created with params [#{#diagnosis.attributes.inspect}" #for debugging
redirect_to #diagnosis
else
flash[:alert] = "Diagnosis not created."
render :action => "new"
end
end
.. other controller actions - edit, show, destroy
end
I also changed the view to replace the check_box_tag with a check_box.
View (_form.html.erb)
<%= form_for(#daignosis) do |f| %>
<div class="field">
<%= f.label :code %>
<%= f.text_field :code %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.check_box 'do_not_correctcase' %><%= f.label "Leave as entered" %><br />
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
So despite getting this to work I'm not clear on are the following:
When inspecting the attributes with "#{#diagnosis.attributes.inspect}".
I assume that the reason the attr_accessor variable is not included in the New diagnosis output is that it is not part of the database table and therefore Active Reocrd does not instanciate it as part of the new record with #diagnosis.new
Could someone be kind enough to confirm that.
Why does the log have no value for logger.debug "code has value #{params[:code]}"? What causes the params[:code] to be null in the logger output?
Logfile contained the following entry:
Started POST "/diagnoses" for 127.0.0.1 at 2012-03-05 09:36:38 +0000
Processing by DiagnosesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"RW/mzkhavGeaIW0hVLn0ortTnbCDlrX+FfzH4neLLsA=", "diagnosis"=>{"code"=>"tt02", "description"=>"description for tt02", "do_not_correctcase"=>"1"}, "commit"=>"Create Diagnosis"}
New diagnosis: {"code"=>"tt02", "created_at"=>nil, "description"=>"description for tt02", "updated_at"=>nil}
Diagnosis should be valid: true
code has value
I would dearly like to know what is the correct way to do all this, as I feel this is not very DRY or clean.

2 render templates (from devise) on one page (rails 3)

I've installed devise for my rails app, i can go to the sign in page or the sign up page. But I want them both on a welcome page...
So I've made a welcome_page_controller.rb with the following function:
class WelcomePageController < ApplicationController
def index
render :template => '/devise/sessions/new'
render :template => '/devise/registration/new'
end
end
But when i go to the welcome page i get this error:
NameError in Welcome_page#index
Showing /Users/tboeree/Dropbox/rails_projects/rebasev4/app/views/devise/sessions/new.html.erb where line #5 raised:
undefined local variable or method `resource' for #<#<Class:0x104931c>:0x102749c>
Extracted source (around line #5):
2: <% #header_title = "Login" %>
3:
4:
5: <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
6: <p><%= f.label :email %><br />
7: <%= f.email_field :email %></p>
8:
Does anybody knows a solution for this problem? Thanks in advance!
Does it have to do with the fact that it is missing the resource function? in the welcome_page controller? It's probably somewhere in the devise controller...?
Regards,
Thijs
Here's how I managed to did it.
I've put a sign up form in my home#index
My files:
view/home/index.html.erb
<%= render :file => 'registrations/new' %>
helper/home_helper.rb
module HomeHelper
def resource_name
:user
end
def resource
#resource = session[:subscription] || User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
def devise_error_messages!
return "" if resource.errors.empty?
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
sentence = I18n.t("errors.messages.not_saved",
:count => resource.errors.count,
:resource => resource_name)
html = <<-HTML
<div id="error_explanation">
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
html.html_safe
end
end
You need that part because Devise works with something called resource and it should be defined so you can call your registration#new anywhere.
Like that, you should be able to register. However, I needed to display errors on the same page. Here's what I added:
layout/home.html.erb (the layout used by index view)
<% flash.each do |name, msg| %>
# New code (allow for flash elements to be arrays)
<% if msg.class == Array %>
<% msg.each do |message| %>
<%= content_tag :div, message, :id => "flash_#{name}" %>
<% end %>
<% else %>
# old code
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %> #don't forget the extra end
<% end %>
I found this code here
And here's something I created: I saved my resource object if invalid in a session so that the user hasn't to fill every field again. I guess a better solution exists but it works and it's enough for me ;)
controller/registration_controller.rb
def create
build_resource
if resource.save
if resource.active_for_authentication?
# We delete the session created by an incomplete subscription if it exists.
if !session[:subscription].nil?
session[:subscription] = nil
end
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => redirect_location(resource_name, resource)
else
set_flash_message :notice, :inactive_signed_up, :reason => resource.inactive_message.to_s if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords(resource)
# Solution for displaying Devise errors on the homepage found on:
# https://stackoverflow.com/questions/4101641/rails-devise-handling-devise-error-messages
flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages
# We store the invalid object in session so the user hasn't to fill every fields again.
# The session is deleted if the subscription becomes valid.
session[:subscription] = resource
redirect_to root_path #Set the path you want here
end
end
I think I didn't forget any code. Feel free to use whatever you need.
Also, you can add your sign in form in the same page (something like that:)
<%= form_for("user", :url => user_session_path) do |f| %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.submit 'Sign in' %>
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
<%= link_to "Forgot your password?", new_password_path('user') %>
<% end %>
Cheers !