Rails 3 validations and non REST URLs - ruby-on-rails-3

I have a route setup like this:
match '/:url' => 'subjects#show'
In my Subjects controller I use
#subject = Subject.where("url = ?", params[:url].downcase).first
instead of
#subject = Subject.find(params[:id])
and this works just fine. The problem is that none of my validation work for the Subject model.
validates :url, :uniqueness => true
This above validation does not work and I get this but only when the url already exists:
SQL (0.5ms) BEGIN
Subject Load (0.3ms) SELECT `subjects`.`id` FROM `subjects` WHERE (`subjects`.`url` = BINARY '78') LIMIT 1
SQL (0.2ms) ROLLBACK
SQL (0.2ms) BEGIN
CACHE (0.1ms) SELECT `subjects`.`id` FROM `subjects` WHERE (`subjects`.`url` = BINARY '78') LIMIT 1
SQL (0.1ms) ROLLBACK
I get forwarded to the existing record's subjects/show as if everything's great. Otherwise, when the url is unique, the exact same SQL query does not get rolled back and the record is created.
Any ideas how I should tackle this? Is this related to my custom subject routes? I'm pulling my hair out. Here's the rest of my routes:
match '/auth/:provider/callback' => 'authentications#create'
match '/about' => 'pages#about'
match '/dashboard' => 'subjects#index', :as => 'user_root'
get "pages/home"
get "pages/about"
resources :authentications
devise_for :admins
devise_for :users, :controllers => {:registrations => 'registrations'}
resources :subjects do
member do
get 'stats'
get 'comments'
get 'qrcode'
get 'download_qrcode'
end
end
resources :traits
resources :ratings
resources :assets
match '/:url/stats' => 'subjects#stats'
match '/:url/remove' => 'subjects#remove'
match '/:url/comments' => 'subjects#comments'
match '/:url/edit' => 'subjects#edit'
match '/:url' => 'subjects#show'
root :to => "pages#home"

I think your routes file is OK.
Usually ActiveRecord rollback selects when you already have duplicated entries in your table, like multiple null or blank entries.
If you set the uniqueness validation after populate the table and you don't set an index into your migration file, probably that's the problem.
In this case, you can do:
Insert index into your migration file:
class CreateSubjects < ActiveRecord::Migration
def change
...
end
add_index :subjects, :url, :unique => true
end
Redo migrations and seed the table.
If this doesn't work, please send your migration file and active_record model.

Related

Singular route serving parameter :object_id instead of :id

Say I have an object called invoice. In routes.rb I have
resources :invoices do
get "pay"
end
When I run rake routes, the route is generated as
invoice_pay GET /invoices/:invoice_id/pay(.:format) invoices#pay
and the parameter is :invoices_id instead of :id
If I use a match statement:
match "invoices/:id/pay" => "invoices#pay", :via => :get
I get:
GET /invoices/:id/pay(.:format) invoices#pay
It seems to me that the route should be pay_invoice_path(#invoice), however, I have not found suitable documentation on this. Any suggestions?
i think what you are trying to do is
resources :invoices do
get "pay", :on => :member
end
have a look at the guides: http://guides.rubyonrails.org/routing.html

rails adding "static_content" on routes

I have routes that work perfectly on one machine, but on another machine they are failing and I've had a hard time to figure out what is wrong. On the failing machine it return the following errors for get /groups/my and groups/ respectively
No route matches {:controller=>"groups/owner/static_content", :topic=>"general"}
No route matches {:controller=>"groups/static_content", :topic=>"general"}
I have no idea where
static_controller
and
:topic=>"general"
come from since they don't appear anywhere in my routes file. Basically I have a route like
namespace :groups , :as => nil do
root :to => 'groups#index'
resources :groups, :only => [:show, :new, :create], :path => '' do
collection do
get :search
get 'my' => 'owner/groups#my', :as => :my
end
member do
post :subscribe
end
... other resources within a group
end
end
Any idea what I have done wrong or I'm missing? I'm using rails 3.2.2 and ruby 1.9.3 on rvm
A route is usually called from the views, so always check your view for action_controller_name_path if Controller::Action can not be found!

rails routes optional parameters types by :id or :name

Scenario:
I would like to have a url path where you could look someone up by an :id or :name:.
For user/5 or /user/tom would all point to the same user
routes.rb
controller 'user' do
get 'user/:id'
get 'user/:name'
end
test/routes/user_routes.rb
test "/user/:id" do
assert_routing "/user/5", :controller => "user", :action => "find_by_id", :id=>"5"
end
test "/user/:name" do
assert_routing "/user/tom", :controller => "user", :action => "find_by_name", :name=>"tom"
end
I am not exactly sure if this is the right design decision with URL paths.
Looking for guidance
I don't think what you are doing is going to work, because the routes you gave are ambiguous, because rails routes can't say that url like user/15 has name or id.
Of course there is a way to do this, by specifying regular expression. Since id will always be a number, we can have regular expression check for it
controller 'user' do
get 'user/:id', :id => /\d+/
get 'user/:name', :name => /[A-Za-z][\w\s]+/
end
The above statements put a constraint of regular expression. In your controller you can check like
if params[:id]
# Get by id
else
# Get by name
You can also do this by passsing get parameters and handling it in controller in the same way.
Thanks

Correct routing for short url by username in Rails

I am trying to replace user profile views of the sort
/users/1
with
/username
I'm aware this means I'll need to check for collisions of various kinds. I've consulted the following similar SO questions:
Ruby on rails routing matching username
customize rails url with username
Routing in Rails making the Username an URL:
routing error with :username in url
Here are the various failed routes.rb route definitions I've tried, and associated errors:
match "/:username" => "users#show", via: "get"
Here's the error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User without an ID
app/controllers/users_controller.rb:7:in `show'
Here is my corresponding users_controller:
6 def show
7 #user = User.find(params[:id])
8 end
match "/:username" => 'users#show', :as => :profile
Same error as above.
match "/:username", :controller => "users/:id", :action => 'show'
Routing Error
uninitialized constant Users
Try running rake routes for more information on available routes.
match '/:username', :controller => 'users', :action => 'show'
Same error as 1.
match '/:username', to: 'users/:id', via: 'show'
Server does not start.
match "/:username" => redirect("/users/:id")
Error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with id=:id
Any idea why my routing is not working the same way that everyone else who asks this question's is?
Update
Just to take this issue out of the comments and put it in the question more cleanly. After making the change by #Ryan Bigg below, I had a routing problem in my redirect to profile when a new one is created. Here's my create code:
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
flash[:success] = "Thank you for signing up."
redirect_to ('/'+#user.username)
#redirect_to #user, notice: "Thank you for signing up!"
else
render "new"
end
end
And here is my user.rb
def to_param
self.username
#username
end
However, the commented out redirect, which I think should work with the to_param update, doesn't work, while the ugly hackish one above it does. Why is the to_param overwrite, which worked for other people, not working on my app? My #update and #edit methods are also not working, as their redirects go to "users/1/edit" instead of "username/edit" if overwriting to_param doesn't take care of this.
The first one is correct, but isn't working because you're still attempting to do something like this inside your controller:
User.find(params[:username])
When you should instead be doing this:
User.find_by_username!(params[:username])
The first one will attempt to find by the primary key of your table, where the second one will, correctly, query on the username field instead.
In addition to the update for to_params, the bottom of the routes file needs the following line:
resources :users, :path => '/'

after_validation find existing record's id in Rails

I'm fairly new to Ruby on Rails and within my app the user is able to create a 'build' record that will only be saved if the entire record is unique. If a user tries to create an existing 'build' / record and the validation fails, I need to be able to redirect that user to the existing record.
As I have stated, I am a novice and made a valiant attempt at using the parameters passed to my create action as so:
def create
#build = Build.new(params[:build])
if #build.save
redirect_to :action => 'view', :id => #build.id
else
#bexist = Build.find(params[:build])
redirect_to :action => 'view', :id => #bexist.id
end
end
Clearly this isn't correct... I also tried to look into callbacks with after_validation, but wasn't sure how to access or even store the existing record's id. Anyone have any suggestions?
You need the attribute/value hash to be passed as the :conditions option, and you need to specify :first, :last, or :all as the first argument.
#bexist = Build.find(:first, :conditions => params[:build])
Alternatively, you can use the #first method instead of using #find with a :first argument.
#bexist = Build.first(:conditions => params[:build])
In Rails 3, you have yet another option...
#bexist = Build.where(params[:build]).first