Routes. Rails 3 - ruby

I update apllication from rails 2 to rails 3.
And I rewrite routes with resources. How to write route to this actions:
def delete_attachment
#object = Article.find(params[:id])
attachment = Attachment.find(params['attachment_id'])
attachment.attachment = nil
attachment.destroy
redirect_to :action => 'edit', :id => #object.id
end
def edit_attachment
#object = Article.find(params[:id])
attachment = Attachment.find(params['attachment_id'])
attachment.title = params['attachment_title']
attachment.description = params['attachment_description']
attachment.save
redirect_to :action => 'edit', :id => #object.id
end
def add_attachment
#object = Article.find(params[:id])
attachment = Attachment.new
attachment.attachment = params['attachment_file']
attachment.title = params['attachment_title']
attachment.description = params['attachment_description']
attachment.article_id = #object.id
attachment.save
params['attachment_title'] = nil
params['attachment_description'] = nil
redirect_to :action => 'edit', :id => #object.id
end
This is right solution?
resources :articles do
delete '/articles/delete_attachment', :to => 'articles#delete_attachment'
put '/articles/edit_attachment', :to => 'articles#edit_attachment'
post '/articles/add_attachment', :to => 'articles#add_attachment'
end
I have no way to check it on the server, because there are still many incompatibilities.

You can change the routes to:
resources :articles do
member do
delete 'delete_attachment'
put 'edit_attachment'
post 'add_attachment'
end
end

If you don't have multiple member routes, you can also pass :on to a route, eliminating the block:
Like,
resources :photos do
get 'preview', on: :member
end

Related

RSpec for routes and testing routes.rb specifically

I'm trying to write test for my costume routes, along with non existing routes.
For the examples down here I have two problems:
It matches the actions that don't exist on my controller, so it doesn't really match to see if my controller have those actions, it just matches the syntax
the should_not be_routable doesn't work, which kind of goes back to the above problem of it doesn't check against my controller or the routes.rb file to see if the route should exist.
This one passes and is all good:
it "should route to method1" do
{ :get => '/my_controller/method1' }.should route_to(:controller => 'my_controller',
:action => 'method1')
end
this one fails, so it doesn't even check to see if I have a method zz defined in my controller or routes file.
it "should not route to zz" do
{ :get => '/my_controller/zz' }.should_not be_routable
end
the error I get is:
MyController routing zz should route to rescan
Failure/Error: { :get => '/my_controller/zz' }.should_not be_routable
expected {:get=>"/client_rescan/zz"} not to be routable, but it routes to {:controller=>"my_controller", :action=>"zz"}
So it obviously doesn't look at my routes file at all...
This is another example of it doesn't look at my routes file, in my routes I have ' resources :client_rescan, :only => [:index] ' and when I do rake routes it doesn't show delete as expected, but the test doesn't look at those:
it "should not have route to delete" do
{ :delete => '/my_controller/1'}.should_not be_routable
end
The Failure I get is the following. Which looks like it doesn't even see the delete function:
Failure/Error: { :delete => '/my_controller/1'}.should_not be_routable
expected {:delete=>"/my_controller/1"} not to be routable, but it routes to {:controller=>"my_controller", :action=>"1"}
Another problem is my post routes to index in the test:
it "should not have route to post" do
{ :post => '/my_controller' }.should_not be_routable
end
The Failure I get is:
Failure/Error: { :post => '/my_controller' }.should_not be_routable
expected {:post=>"/my_controller"} not to be routable, but it routes to {:controller=>"my_controller", :action=>"index"}
this is content of my routes.rb file
require 'resque/server'
require 'resque_scheduler'
Cdc::Application.routes.draw do
mount Resque::Server.new, :at => 'resque'
Resque.schedule = YAML.load_file(File.join(File.dirname(__FILE__), 'resque_schedule.yml')) # load the schedule
devise_for :users, :controllers => { :sessions => "sessions", :registrations => "registrations" }
[:assessments, :security_assessments, :privacy_assessments].each do |assessment_type|
resources assessment_type, :controller => :assessments do
resources :rsz do
post 'review', :on => :member
get 'judgement', :on => :member
end
get :judgement, :on => :member
resources :samples do
get 'download', :on => :member
end
resources :asm_reviews do
post :request_review, :on => :collection
end
end
end
resources :account_creator
match "/images/captcha/*file_name" => "captcha#show"
## this is where my route is!! :)
resources :my_controller, :only => [:index] do
collection do
get :rescan
get :cancel
end
end
match "alert_queue/words" => "alert_queue#words"
resources :alert_queue
match "calls_to_action/start/:id" => "calls_to_action#start", :id => /\d+/
match "calls_to_action/close/:id" => "calls_to_action#close", :id => /\d+/
match "calls_to_action/comment/:id" => "calls_to_action#comment", :id => /\d+/
match "calls_to_action/multiclose" => "calls_to_action#multiclose"
match "calls_to_action/multiscan" => "calls_to_action#multiscan"
match "application_instances/multiclose" => "application_instances#multiclose"
match "application_instances/multiscan" => "application_instances#multiscan"
resources :code_categories do
resources :code_families do
resources :code_family_versions
end
end
resources :code_policy_items
resources :application_instances do
collection do
post :resque_statuses
end
resources :code_indices
resources :application_analysis
get "smali/:smali_path", :as => :smali, :on => :member, :action => :smali, :smali_path => /.*/
member do
get :file
get :strings
get :dump
get :alerts
get :correlations
get :signers
get :icon
get :resque_status
get :assets
get :new_code_index
get :class_list
get :heuristic_hits
get :engine_artifacts
post :rescan
post :attach_artifact
post :engine_artifact, :action => :attach_engine_artifact
resources :alerts
end
post "multiscan", :on => :collection, :action => :multiscan
post "multiclose", :on => :collection, :action=> :multiclose
post "engines/:engine_name/:engine_version/assertions/:cookie",
:on => :member, :action => :register_assertion_set, :as => :register_assertion_set,
:engine_name => /[^\/]+/, :engine_version => /[^\/]+/, :cookie => /[^\/]+/
post "engines/:engine_name/:engine_version/network_data",
:on => :member, :action => :register_network_data, :as => :register_network_data,
:engine_name => /[^\/]+/, :engine_version => /[^\/]+/
post "assets", :on => :member, :action => :register_asset_set, :as => :register_asset_set
end
# index gets the list of families, show gets the assertion types for that family
resources :assertion_families
resources :artifacts
resources :dashboard do
collection do
get :last_app_instance
end
end
match '/direct_downloads/' => 'direct_downloads#index'
root :to => "stats#index"
match '/' => 'stats#index'
match 'explorer/query/:format' => 'explorer#query'
match '/:controller(/:action(/:id))'
end
The problem is this line of routes.rb:
match '/:controller(/:action(/:id))'
This is a catch all route, and will match for example /abc/xyz to controller abc, and action xyz.
It's best really not to use catch all routes, in favour of exposing only the functionality you want.

Rails form validation works in one template but not another for the same Model

Another hair-puller. AFter two days of fighting with this I cannot figure out what is wrong here.
Basically I have a form validation triggered by the model:
validates :user, :presence => true, :uniqueness => true
validates :email, :presence => true, :uniqueness => true, :on => :create
validates :passwordHash, :presence => true, :confirmation => true, :on => :create
The user not being empty works on the update form View:
= simple_form_for #user do |f|
= f.input :user
= f.input :locale
= f.input :localeLanguage, :label => 'Language', :as => :select, :collection => $language_array
= f.input :moderator
= f.input :email
= f.input :passwordHash, :label => 'Password'
But not on the new users View:
= simple_form_for #user do |f|
%table.table-condensed
%tr
%td
=f.input :user, :label => false, :placeholder => 'username'
%tr
%td
= f.input :passwordHash, :label => false, :placeholder => 'password'
%tr
%td
= f.input :email, :label => false, :placeholder => 'email'
%tr
%td
= f.submit "Create User", :class => 'btn btn-primary'
The only difference I can see between these views is that the first one has sessions created since a user has already logged in, the second one doesn't. But as far as I know this should not make a difference. Of course, the update form does have an actual #user object whereas in the new one it is empty. But I've seen Ryan Bates' railscast of a new user validation and he does pretty much the same thing.
What happens is the users#create action being invoked after submitting the form with empty values (which should not be possible). Of course I get an error because the passwordHash is empty.
I should point out that I'm not using any extra gems to aid in password confirmation (in the railscast, Bates uses bcrypt but I can't use it because we create the password hash a different way plus I think that's for the password confirmation magic only). In any case this should not affect the form validation should it?
Any theories or ideas are welcome here, I'm going crazy. I'm about to write some crappy javascript to do it by hand which would be awful and would probably take me a week, I don't do javascript ;)
Thanks.
Edit
Per Rachid's request, here are the new and create actions:
def new
#user = User.new
end
def create
#failsafe for failing form validation
unless params[:passwordHash].present?
redirect_to new_user_path, :notice => 'User or password cannot be blank'
else
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt)
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
redirect_to new_user_path, :notice => "User already exists, please pick another one"
end
end
end
Edit 2
I've rewritten the create method based on the first answer, but still getting an error:
def create
respond_to do |format|
if params[:passwordHash].present? && params[:user].present?
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt, :online_user => 1 )
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
The error is undefined method 'model_name' for NilClass:Class for this line:
= simple_form_for #user do |f|
Obviously the #user = User.new is not making it back to the form. At this point I'm a little confused as to how I should write the create method for it to work properly and show the error messages. But I feel I'm closer :)
#misha, here is the update controller action, it's just pretty standard scaffolding:
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
if session[:return_to]
format.html { redirect_to session[:return_to], :notice => 'User was successfully updated.' }
else
format.html { redirect_to users_path, :notice => 'User was successfully updated.' }
end
format.json { head :ok }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
First of all what you assume here is incorrect:
What happens is the users#create action being invoked after submitting
the form with empty values (which should not be possible). Of course I
get an error because the passwordHash is empty.
It is possible that users#create is invoked and actually it should happen. It is in the create action where you handle this stuff. I think your problem is the fact that you do a redirect if the #user is not saved. You should render the view again, so the error messages can be displayed.
So instead of:
redirect_to new_user_path, :notice => "User already exists, please pick another one"
Try:
render :action => 'new'
Edit based on your comment:
When validation fails Rails populates #user.errors automatically. You don't have to do anything in the controller (i.e. your create action)! All you have to do is display the errors in #user.errors in your view.
About the error you are getting now:
The reason you are getting the error is that #user is not set. You have to rewrite your create method to something like this:
def create
respond_to do |format|
if params[:user][:passwordHash].present?
password_and_salt = User.hash_password(params[:user][:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
end
#user = User.new(params[:user].merge({:passwordHash => hashed_password, :salt => user_salt, :online_user => 1}))
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end

best_in_place gem to edit currency

I'm using the best_in_place gem to edit balances:
index.html.erb:
<%= best_in_place bankaccount, :balance, :display_with => :number_to_currency %>
but after editing, I get a unformatted number ($45 changed to 46 shows as 46).
How do I get best_in_place to display the new value as $$$?
controller:
respond_to :html, :json
...
def update
#bankaccount = Bankaccount.find(params[:id])
if #bankaccount.update_attributes(params[:bankaccount])
respond_with #bankaccount
else
render :json => #bankaccount.errors.full_messages, :status => :unprocessable_entity
end
# if #bankaccount.update_attributes(params[:bankaccount])
# redirect_to #bankaccount, :notice => "Successfully updated bankaccount."
# else
# render :action => 'edit'
# end
end
This thread is already answered but I tried the accepted answer and it didn't work.
However using a lambda everything is nice again. Rails 4, by the way.
<%= best_in_place #text, :body, :type => :textarea, :display_with => lambda{ |v| markdown(v) }, :html_attrs => { :class => 'edit-text-body' } %>
Ended up using BIP's :display_as => :mk_bal with mk_bal defined in model Bankaccount as:
def mk_bal
ActionController::Base.helpers.number_to_currency(self.balance, :precision => 2)
end

Undefined method 'title' for nil:NilClass

I am following railsspace book but when i trying edit show and eliminate a post owner (chapter 15) I get: error message
undefined method `title' for nil:NilClass
follow extact:
1: <div class="post">
2: <div class="post_title">
3:
4: <%= sanitize post.title %>
5: <% unless hide_edit_links? %>
6: <span style="float:right">
7: <%= link_to_unless_current 'Mostrar', blog_post_path(post.blog, post) %> |
Ruby 1.9.2
Rails 3.1.3
The controller, views and routes is as follow:
Controller: posts_controller
# Encoding: UTF-8
class PostsController < ApplicationController
helper :profile
before_filter :protect, :protect_blog
# GET /posts
# GET /posts.xml
def index
#Recheck implement paginate for Rails 3.1.3
##pages, #posts = paginate(#blog.posts)
#posts = #blog.posts
#title = "Administración del Blog"
respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => #posts.to_xml }
end
end
# GET /posts/1
# GET /posts/1.xml
def show
#post = Post.find(params[:id])
#title = #post.title
respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => #post.to_xml }
end
end
# GET /posts/new
def new
#post = Post.new
#title = "Nuevo post"
end
# GET /posts/1;edit
def edit
#post = Post.find(params[:id])
#title = "Edit #{#post.title}"
end
# POST /posts
# POST /posts.xml
def create
#post = Post.new(params[:post])
#post.blog = #blog
respond_to do |format|
if #post.duplicate? or #blog.posts << #post
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to blog_post_url(:id => #post) }
format.xml { head :created, :location => blog_post_url(:id => #post) }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors.to_xml }
end
end
end
# PUT /posts/1
# PUT /posts/1.xml
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to post_url(:id => #post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors.to_xml }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.xml
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.xml { head :ok }
end
end
private
# Ensure that user is blog owner, and create #blog.
def protect_blog
#blog = Blog.find(params[:blog_id])
user = User.find(session[:user_id])
unless #blog.user == user
flash[:notice] = "That isn't your blog!"
redirect_to hub_url
return false
end
end
end
View: index
<h2>Sus Blog Posts</h2>
<p class="edit_link">
<%= link_to 'Agregar nuevo post', new_blog_post_path %>
<%= "| Pages: #{pagination_links(#pages)}" if paginated? %>
</p>
<%= render :partial => "post", :collection => #posts %>
View: post
<div class="post">
<div class="post_title">
<%= sanitize post.title %>
<% unless hide_edit_links? %>
<span style="float:right">
<%= link_to_unless_current 'Mostrar', blog_post_path(post.blog, post) %> |
<%= link_to_unless_current 'Editar', edit_blog_post_path(post.blog, post) %> |
<%= link_to 'Eliminar', blog_post_path(post.blog, post),
:confirm => 'Deseas eliminar este post?', :method => :delete %>
</span>
<% end %>
</div>
<div class="post_body"><%= sanitize post.body %></div>
<div class="post_creation_date">
Publicado <%= time_ago_in_words post.created_at %> ago
<% if post.updated_at != post.created_at %>
<br /> Modified <%= time_ago_in_words post.updated_at %> ago
<% end %>
</div>
</div>
In this view , i has triying put # in the variable post =#post, but it not work
Routes
Expression::Application.routes.draw do
get "email/remind"
get "avatar/index"
get "avatar/upload"
get "avatar/delete"
get "community/index"
get "community/browse"
get "community/search"
get "faq/index"
get "faq/edit"
get "spec/index"
get "spec/edit"
get "profile/index"
get "profile/show"
get "user/index"
get "user/register"
get "site/index"
get "site/about"
get "site/help"
get "user/login"
get "user/logout"
get "user/edit"
get "user_mailer/welcome_email"
post "user/register"
post "user/login"
post "user/edit"
post "spec/edit"
post "faq/edit"
post "community/index"
post "community/search"
post "avatar/upload"
post "email/remind"
resources :blogs do
resources :posts
end
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
# root :to => 'welcome#index'
root :to => 'site#index'
# match'', :controller => 'site', :action => 'index', :id => nil
resources :user
match '/register', :to => 'user#register'
match '/about', :to => 'user#about'
match '/help', :to => 'user#help'
match '/login', :to =>'user#login'
match '/edit', :to =>'user#edit'
match '/user/welcome_email', :to => 'user#create'
#resources :profile
#match '/show', :to => 'profile#show'
# Install the default route as the lowest priority.
match ':controller/:action/:id'
match 'profile', :to => 'profile#show', :as => "profile"
match 'hub', :to => 'user#index', :as => 'hub'
##Change Route pagina 343
# You can have the root of your site routed by hooking up ''
# -- just remember to delete public/index.html.
match '', :controller => 'site', :action => 'index', :id => nil
###
#match'', :controller => 'user', :action => 'about', :id => nil
#match'', :controller => 'user', :action => 'help', :id => nil
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id(.:format)))'
end
ApplicationStacktrace
app/views/posts/_post.erb:4:in `_app_views_posts__post_erb__1793130860277527745_40556500'
app/views/posts/show.html.erb:3:in `_app_views_posts_show_html_erb__2356198700875868089_40643800'
app/controllers/posts_controller.rb:23:in `show
Use #post.title, instead of post.title on line 4 of your template.
After deleting your code is trying to redirect to posts_url.
However I do not see that in your routes. btw you can also do rake routes at the command line to see what your routes are.
I think you need to add a get for posts/index although I would really look to try and use RESTful routing which would clean up much of your routes.

How do I create a email confirmation?

I'm trying to make a simple email notification when a user signs up.
My user sign up works fine, and I followed the "Sending Email" tutorial exactly but can't get it to work. What am I doing wrong?
user_controller.rb
class Admin::UsersController < InheritedResources::Base
before_filter :admin_only
actions :index, :show, :new, :edit, :create, :update, :destroy
respond_to :html
# def new
# #user = User.new(:invitation_token => params[:invitation_token])
# #user.email = #user.invitation.recipient_email
# end
def create
#user = User.new(params[:user])
UserMailer.deliver_registration_confirmation(#user) < -- where I added the mailer
#user.save(false)
respond_to do |format|
format.html{ redirect_to admin_users_path}
end
end
private
def collection
paginate_options ||= {}
paginate_options[:page] ||= (params[:page] || 1)
paginate_options[:per_page] ||= (params[:per_page] || 20)
#search = User.search(params[:search])
#users ||= #search.all.paginate(paginate_options)
end
end
environments/production.rb
# Settings specified here will take precedence over those in config/environment.rb
config.action_mailer.default_url_options = { :host => 'alpine.totaline.com' }
config.action_mailer.raise_delivery_errors = true
# set delivery method to :smtp, :sendmail or :test
config.action_mailer.delivery_method = :smtp
# these options are only needed if you choose smtp delivery
config.action_mailer.smtp_settings = {
:address => 'smtp.gmail.com',
:port => 25,
:domain => 'alpine.totaline.com',
:authentication => :login,
:user_name => 'emailname#gmail.com',
:password => 'thepassword'
}
models/user_mailer.rb
class UserMailer < ActionMailer::Base
def registration_confirmation(user)
recipients user.email
from "webmaster#alpinechallenge.com"
subject "Thank you for Registering"
body "You are now registered on the Alpine Challenge!"
end
end
Looks like for Gmail you need to use port 587:
# these options are only needed if you choose smtp delivery
config.action_mailer.smtp_settings = {
:address => 'smtp.gmail.com',
:port => '587',
:domain => 'alpine.totaline.com',
:authentication => :login,
:user_name => 'emailname#gmail.com',
:password => 'thepassword'
}
This page contains notes about configuring mail clients for usage with Gmail.

Resources