Reputation: 2305
[Update] Code is little canged because I realized that I need more generation pictures for one school (one for each generation) so associations are different now.
I have a School model with GenerationPicture:
class School < ActiveRecord::Base
belongs_to :city
has_many :sclasses
has_many :users, through: :sclasses
has_many :generation_pictures
validates :name, presence: true
validates :icon_url, length: { maximum: 100 }
end
class GenerationPicture < ActiveRecord::Base
validates :generation, presence: true, numericality: { only_integer: true }, uniqueness: true
has_attached_file :image, styles: { large: "600x600", medium: "300x300>", thumb: "150x150" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
belongs_to :school
end
This is my generation_pictures controller:
class GenerationPicturesController < ApplicationController
def new
find_city
find_school
@generation_picture = @school.generation_pictures.new
end
def create
find_city
find_school
@generation_picture = @school.generation_pictures.new(generation_picture_params)
if @generation_picture.save
redirect_to generation_picture_path(@generation_picture)
else
render "new"
end
end
def edit
find_city
find_school
find_generation_picture
end
def update
find_city
find_school
find_generation_picture
if @generation_picture.update(generation_picture_params)
redirect_to generation_picture_path(@generation_picture)
else
render "edit"
end
end
private
def generation_picture_params
params.require(:generation_picture).permit(:generation, :image)
end
def find_city
@city = City.find(params[:city_id])
end
def find_school
@school = School.find(params[:school_id])
end
def find_generation_picture
@generation_picture = @school.generation_pictures.find(params[:id])
end
end
When I try to access the page for new picture I'm returned to the index page and console shows no errors.
Here are routes:
Rails.application.routes.draw do
root 'welcome#index'
# prevedene rute
get "/pocetna" => "welcome#index", as: "index"
get "/korpa" => "carts#new", as: "new_cart"
get "/poslato" => "carts#success", as: "success"
resources :sessions, only: [:new, :create, :destroy]
get "/prijava" => "sessions#new", as: "login"
post "/prijava" => "sessions#create"
get "/odjava" => "sessions#destroy", as: "logout"
delete "/odjava" => "sessions#destroy"
#resources :users do
# resources :photos
#end
# Gradovi
get "/gradovi" => "welcome#index", as: "cities"
get "/gradovi/novi" => "cities#new", as: "new_city"
post "/gradovi" => "cities#create"
get "/gradovi/:id" => "cities#show", as: "city"
get "/gradovi/:id/uredi" => "cities#edit", as: "edit_city"
patch "/gradovi/:id" => "cities#update"
# Škole
get "/gradovi/:city_id" => "schools#index", as: "schools"
get "/gradovi/:city_id/nova-skola" => "schools#new", as: "new_school"
post "/gradovi/:city_id/" => "schools#create"
get "/gradovi/:city_id/skola/:id" => "schools#show", as: "school"
get "/gradovi/:city_id/skola/:id/uredi" => "schools#edit", as: "edit_school"
patch "/gradovi/:city_id/skola/:id" => "schools#update"
# Tabloi
get "/gradovi/:city_id/skola/:school_id/tablo/novi" => "generation_pictures#new", as: "new_generation_picture"
post "/gradovi/:city_id/skola/:school_id" => "generation_pictures#create"
get "/gradovi/:city_id/skola/:school_id/tablo/:id" => "generation_pictures#show", as: "generation_picture"
get "/gradovi/:city_id/skola/:school_id/tablo/:id/uredi" => "generation_pictures#edit", as: "edit_generation_picture"
patch "/gradovi/:city_id/skola/:school_id" => "generation_pictures#update"
# Razredi
get "/gradovi/:city_id/skola/:school_id" => "sclasses#index", as: "sclasses"
post "/gradovi/:city_id/skola/:school_id" => "sclasses#create"
get "/gradovi/:city_id/skola/:school_id/razred/dodaj" => "sclasses#new", as: "new_sclass"
get "/gradovi/:city_id/skola/:school_id/razred/:id" => "sclasses#show", as: "sclass"
get "/gradovi/:city_id/skola/:school_id/razred/:id/uredi" => "sclasses#edit", as: "edit_sclass"
patch "/gradovi/:city_id/skola/:school_id/razred/:id" => "sclasses#update"
# Učenici
get "/gradovi/:city_id/skola/:school_id/razred/:sclass_id" => "users#index", as: "users"
post "/gradovi/:city_id/skola/:school_id/razred/:sclass_id" => "users#create"
get "/gradovi/:city_id/skola/:school_id/razred/:sclass_id/ucenik/dodaj" => "users#new", as: "new_user"
get "/gradovi/:city_id/skola/:school_id/razred/:sclass_id/ucenik/:id" => "users#show", as: "user"
get "/gradovi/:city_id/skola/:school_id/razred/:sclass_id/ucenik/:id/uredi" => "users#edit", as: "edit_user"
patch "/gradovi/:city_id/skola/:school_id/razred/:sclass_id/ucenik/:id" => "users#update"
delete "/gradovi/:city_id/skola/:school_id/razred/:sclass_id/ucenik/:id" => "users#destroy"
resources :city
resources :carts
end
This is the form partial:
<% if controller.action_name == "edit" %>
<%= form_for [@city, @school, @generation_picture], url: generation_picture_path(@city, @school, @generation_picture), html: { multipart: true } do |f| %>
<% if @generation_picture.errors.any? %>
<div class="alert alert-danger">
<ul>
<% @generation_picture.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label "Fotografija:" %>
<%= f.file_field :image, class: "input-field" %>
<%= f.label "Generacija:" %>
<%= f.text_field :generation, class: "input-field" %>
<%= f.submit "Pošalji", class: "btn btn-default" %>
<% end %>
<% else %>
<%= form_for @generation_picture, url: school_path(@city, @school), html: { multipart: true } do |f| %>
<% if @generation_picture.errors.any? %>
<div class="errors alert alert-danger">
<ul>
<% @generation_picture.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label "Fotografija:" %>
<%= f.file_field :image, class: "input-field" %>
<%= f.label "Generacija:" %>
<%= f.text_field :generation, class: "input-field" %>
<%= f.submit "Pošalji", class: "btn btn-default" %>
<% end %>
<% end %>
[Update] Rake routes output
new_generation_picture GET /gradovi/:city_id/skola/:school_id/tablo/novi(.:format) generation_pictures#new
POST /gradovi/:city_id/skola/:school_id(.:format) generation_pictures#create
generation_picture GET /gradovi/:city_id/skola/:school_id/tablo/:id(.:format) generation_pictures#show
edit_generation_picture GET /gradovi/:city_id/skola/:school_id/tablo/:id/uredi(.:format) generation_pictures#edit
PATCH /gradovi/:city_id/skola/:school_id(.:format) generation_pictures#update
schools GET /gradovi/:city_id(.:format) schools#index
new_school GET /gradovi/:city_id/nova-skola(.:format) schools#new
POST /gradovi/:city_id(.:format) schools#create
school GET /gradovi/:city_id/skola/:id(.:format) schools#show
edit_school GET /gradovi/:city_id/skola/:id/uredi(.:format) schools#edit
PATCH /gradovi/:city_id/skola/:id(.:format) schools#update
[Update 2] Current routes
Rails.application.routes.draw do
root 'welcome#index'
get "/korpa" => "carts#new", as: "new_cart"
get "/poslato" => "carts#success", as: "success"
resources :sessions, only: [:new, :create, :destroy]
get "/prijava" => "sessions#new", as: "login"
post "/prijava" => "sessions#create"
get "/odjava" => "sessions#destroy", as: "logout"
delete "/odjava" => "sessions#destroy"
scope(path_names: { new: 'novi', edit: 'uredi' }) do
resources :cities, path: 'gradovi', except: [:index, :destroy] do
scope(path_names: { new: 'nova-skola', edit: 'uredi' }) do
resources :schools, path: 'skola', except: [:index, :destroy], shallow: true do
scope(path_names: { new: 'dodaj', edit: 'uredi'}) do
resources :sclasses, path: 'razred', except: [:destroy] #, shallow: true
scope(path_names: { new: 'dodaj', edit: 'uredi'}) do
resources :users, path: 'ucenik'
end
end
scope(path_names: { new: 'novi', edit: 'uredi'}) do
resources :generation_pictures, path: 'tablo', except: [:index, :destroy]
end
end
end
end
end
resources :carts, except: [:new] # defined at top
end
Upvotes: 0
Views: 71
Reputation: 2549
You have a lot of routes overriding others, such as:
get "/gradovi/:id" => "cities#show", as: "city"
# vs.
get "/gradovi/:city_id" => "schools#index", as: "schools"
and
post "/gradovi/:city_id/skola/:school_id" => "generation_pictures#create"
# vs.
post "/gradovi/:city_id/skola/:school_id" => "sclasses#create"
and
get "/gradovi/:city_id/skola/:school_id/razred/:id" => "sclasses#show", as: "sclass"
# vs
get "/gradovi/:city_id/skola/:school_id/razred/:sclass_id" => "users#index", as: "users"
Rails can't tell whether a number is supposed to be :id
or :city_id
, it just sees a number. Likewise, configuring the same URL to go to multiple controller actions will result in disappointing behavior.
I think a good first step is to simplify your route definitions with nested resources and translated paths.
Rails.application.routes.draw do
root 'welcome#index'
# prevedene rute
#
# another duplicate of root_path:
# get "/pocetna" => "welcome#index", as: "index"
get "/korpa" => "carts#new", as: "new_cart"
get "/poslato" => "carts#success", as: "success"
get "/prijava" => "sessions#new", as: "login"
post "/prijava" => "sessions#create"
get "/odjava" => "sessions#destroy", as: "logout"
delete "/odjava" => "sessions#destroy"
# Gradovi
scope(path_names: { new: 'novi', edit: 'uredi' }) do
resources :cities, path: 'gradovi', except: [:index, :destroy] do
# don't create multiple routes to 'welcome#index',
# use root_url or root_path
# get '/gradovi', to: 'welcome#index', as: 'cities', on: :collection
# Škole
scope(path_names: { new: 'nova-skola', edit: 'uredi' }) do
# use root_url here for 'welcome#index', too
resources :schools, path: 'skola', except: [:index, :destroy] do
# Tabloi
scope(path_names: { new: 'novi', edit: 'uredi'}) do
resources :generation_pictures, path: 'tablo', except: [:index, :destroy]
end
# Razredi
scope(path_names: { new: 'dodaj', edit: 'uredi'}) do
resources :sclasses, path: 'razred', except: [:destroy]
# Učenici
scope(path_names: { new: 'dodaj', edit: 'uredi'}) do
resources :users, path: 'ucenik'
end
end
end
end
end
# You already have `resources :cities` as 'gradovi' above:
# resources :city
resources :carts, except: [:new] # defined at top
end
This is going to change your route helper names that you're using elsewhere in your code, but your routes should be much cleaner now. You should also look into the shallow
routing keyword, because nesting this many deep just to get to your users (for example), is not a great style.
There's no reason why getting a list of students for a class has to include the city in the URL, and nobody wants to type new_city_school_sclass_user_path(@city, @school, @sclass)
, so organize your urls better. It doesn't affect your associations or any app functionality, just the route names and URLs. I suggest putting shallow: true
on schools
:
scope(path_names: { new: 'novi', edit: 'uredi' }) do
# Gradovi
resources :cities, path: 'gradovi', except: [:index, :destroy] do
# don't create multiple routes to 'welcome#index',
# use root_url or root_path
# get '/gradovi', to: 'welcome#index', as: 'cities', on: :collection
# Škole
scope(path_names: { new: 'nova-skola', edit: 'uredi' }) do
# use root_url here for 'welcome#index', too
resources :schools, path: 'skola', except: [:index, :destroy], shallow: true do
# Razredi
scope(path_names: { new: 'dodaj', edit: 'uredi'}) do
resources :sclasses, path: 'razred', except: [:destroy] #, shallow: true
# Učenici
scope(path_names: { new: 'dodaj', edit: 'uredi'}) do
resources :users, path: 'ucenik'
end
end
# Tabloi
scope(path_names: { new: 'novi', edit: 'uredi'}) do
resources :generation_pictures, path: 'tablo', except: [:index, :destroy]
end
end
end
end
end
Which gives you a list of routes like this:
root GET / welcome#index
new_cart GET /korpa(.:format) carts#new
success GET /poslato(.:format) carts#success
login GET /prijava(.:format) sessions#new
prijava POST /prijava(.:format) sessions#create
logout GET /odjava(.:format) sessions#destroy
odjava DELETE /odjava(.:format) sessions#destroy
sclass_users GET /razred/:sclass_id/ucenik(.:format) users#index
POST /razred/:sclass_id/ucenik(.:format) users#create
new_sclass_user GET /razred/:sclass_id/ucenik/dodaj(.:format) users#new
edit_user GET /ucenik/:id/uredi(.:format) users#edit
user GET /ucenik/:id(.:format) users#show
PATCH /ucenik/:id(.:format) users#update
PUT /ucenik/:id(.:format) users#update
DELETE /ucenik/:id(.:format) users#destroy
school_sclasses GET /skola/:school_id/razred(.:format) sclasses#index
POST /skola/:school_id/razred(.:format) sclasses#create
new_school_sclass GET /skola/:school_id/razred/dodaj(.:format) sclasses#new
edit_sclass GET /razred/:id/uredi(.:format) sclasses#edit
sclass GET /razred/:id(.:format) sclasses#show
PATCH /razred/:id(.:format) sclasses#update
PUT /razred/:id(.:format) sclasses#update
school_generation_pictures POST /skola/:school_id/tablo(.:format) generation_pictures#create
new_school_generation_picture GET /skola/:school_id/tablo/novi(.:format) generation_pictures#new
edit_generation_picture GET /tablo/:id/uredi(.:format) generation_pictures#edit
generation_picture GET /tablo/:id(.:format) generation_pictures#show
PATCH /tablo/:id(.:format) generation_pictures#update
PUT /tablo/:id(.:format) generation_pictures#update
city_schools GET /gradovi/:city_id/skola(.:format) schools#index
POST /gradovi/:city_id/skola(.:format) schools#create
new_city_school GET /gradovi/:city_id/skola/nova-skola(.:format) schools#new
edit_school GET /skola/:id/uredi(.:format) schools#edit
school GET /skola/:id(.:format) schools#show
PATCH /skola/:id(.:format) schools#update
PUT /skola/:id(.:format) schools#update
cities POST /gradovi(.:format) cities#create
new_city GET /gradovi/novi(.:format) cities#new
edit_city GET /gradovi/:id/uredi(.:format) cities#edit
city GET /gradovi/:id(.:format) cities#show
PATCH /gradovi/:id(.:format) cities#update
PUT /gradovi/:id(.:format) cities#update
carts GET /carts(.:format) carts#index
POST /carts(.:format) carts#create
edit_cart GET /carts/:id/edit(.:format) carts#edit
cart GET /carts/:id(.:format) carts#show
PATCH /carts/:id(.:format) carts#update
PUT /carts/:id(.:format) carts#update
DELETE /carts/:id(.:format) carts#destroy
Upvotes: 1