I'm build forum rails app, I have problem with nested resources.
here's controller/school/forums_controller.rb
def index
#forums = Forum.all
end
def show
#forum = Forum.find(params[:id])
#per_page = params[:per_page] || 15
#topics = #forum.topics.search(params[:search]).paginate(:per_page => #per_page, :page => params[:page])
end
here's controller/school/topics_controller.rb
def new
#forum = Forum.find(params[:forum_id])
#topik = #forum.topiks.build
end
def create
#forum = Forum.find(params[:forum_id])
#topic = #forum.topics.build(params[:topic])
if #topic.save
redirect_to school_forum_topic_path(#topic)
else
render :action => "new"
end
end
def show
#forum = Forum.find(params[:forum_id])
#topic = Topic.find(params[:id])
end
Here's routes.rb
get '/forum' => 'school/forums#index', :as => :forum_subdomain
namespace :school, :path => '/' do
resources :forums, :path => '/forum', :only => [:show] do
resources :topics
end
end
forum_subdomain GET /forum(.:format)
school/forums#index {:subdomain=>/.+/}
school_forum_topics GET /fr/:forum_id/topics(.:
format) school/topics#index {:subdomain=>/.+/}
POST /forum/:forum_id/topics(.:
format) school/topics#create {:subdomain=>/.+/}
new_school_forum_topic GET /forum/:forum_id/topics/ne
w(.:format) school/topics#new {:subdomain=>/.+/}
edit_school_forum_topic GET /forum/:forum_id/topics/:i
d/edit(.:format) school/topics#edit {:subdomain=>/.+/}
school_forum_topic GET /forum/:forum_id/topics/:i
d(.:format) school/topics#show {:subdomain=>/.+/}
PUT /forum/:forum_id/topics/:i
d(.:format) school/topics#update {:subdomain=>/.+/}
DELETE /forum/:forum_id/topics/:i
d(.:format) school/topics#destroy {:subdomain=>/.+/}
school_forum GET /forum/:id(.:format)
school/forums#show {:subdomain=>/.+/}
when I access subdomain.lvh.me:3000/forum/1-room-biology
Routing Error
No route matches {:action=>"new", :controller=>"school/topics"}
here's views/school/forums/show.html.erb
<%= link_to new_school_forum_topic_path , :class => "btn btn-inverse btn-medium" do %>
New Topic
<% end %>
<% for topic in #topics %>
<%= link_to topic.title, school_forum_topic_path(topic) %>
<% end %>
How do I do this correctly and/or what is the correct way to route all of this?
Your call to new_school_forum_topic_path needs to have the forum provided, eg. new_school_forum_topic_path(#forum).
For more information on nested resource routing in Rails: http://guides.rubyonrails.org/routing.html#nested-resources
Related
I have Photo model which belongs to User model. Rails returns this error whenever I try to access new view for /users/4/photos/new:
No route matches {:action=>"index", :controller=>"photos", :user_id=>"4"} missing required keys: [:id]
This is my PhotosController:
class PhotosController < ApplicationController
def index
find_user
#photos = #user.photos
end
def new
find_user
#photo = #user.photos.build
end
def show
find_photo
end
def create
#photo = Photo.new(params[:photo])
if #photo.save
if params[:images]
params[:images].each { |image|
#user.photos.create(image: image)
}
end
else
render 'new'
end
end
def update
find_user
#photo = #user.photos.find(params[:id])
if #photo.update
redirect_to photos_path
else
render 'edit'
end
end
def destroy
find_photo
#photo.destroy
redirect_to photos_path
end
private
def find_user
#user = User.find(params[:user_id])
end
def find_photo
#photo = Photo.find(params[:id])
end
def photo_params
require(:photo).permit(:title, :image, :user_id)
end
end
And this is my _form partial for photos views.
<%= form_for #photo, :html => { class: 'form-horizontal', multipart: true } do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "input-field form-control" %>
<%= f.label :pictures %>
<%= file_field_tag "images[]", type: :file, multiplue: true %>
<%= f.submit nil, class: "btn btn-primary" %>
I don't understand how ID is missing, I'm providing it via find_user method.
Update:
# routes.rb
Rails.application.routes.draw do
root 'welcome#index'
# prevedene rute
get "/pocetna" => "welcome#index", as: "index"
get "/o-sajtu" => "welcome#about", as: "about"
get "/moj-profil" => "users#show", as: "profile"
post "/users" => "users#create"
get "/users" => "users#index", as: "users"
get "/user" => "users#index"
get "/users/:id" => "users#show", as: "user"
get "/users/:id/edit" => "users#edit", as: "edit_user"
patch "/users/:id" => "users#update"
get "/users/add" => "users#new", as: "new_user"
resources :sessions, only: [:new, :create, :destroy]
get "/login" => "sessions#new", as: "login"
post "/login" => "sessions#create"
get "/logout" => "sessions#destroy", as: "logout"
delete "/logout" => "sessions#destroy"
resources :users do
resources :photos
end
end
Update
I get new error now
undefined method `photos_path' for #<<Class:0x007f4f14f16160>:0x00000004f040e8>
First line of the form is marked.
change your form_for in _form partial to
form_for([#user, #photo]) do |f|
#rest of your code
end
How do you call the /users/4/photos/new in your view? Ideally you should pass the user_id as id not as user_id. Once, you do that this issue should be resolved.
When I call the delete action on my on my index.html.erb page for images, it references the correct id's and such, but it does not order them in the url correctly. The url should look like http://localhost:3000/admin/albums/33/images/1, but it displays as http://localhost:3000/admin/albums/33/images.1. I know it has something to do with the .:format, but I'm not sure how to fix it. When I put this in the delete action, admin_album_images_path([#album, image]), it results in http://localhost:3000/admin/albums/33/1/images.
routes
Admin::Application.routes.draw do
get "albums/index"
get "dashboard/index"
namespace :admin do
root :to => "dashboard#index"
resources :dashboard
resources :albums do
resources :images
end
get "admin/album"
end
get "logout" => "sessions#destroy", :as => "logout"
get "login" => "sessions#new", :as => "login"
get "signup" => "users#new", :as => "signup"
# resources :users
resources :basic
root :to => "basic#index"
Controller
class Admin::ImagesController < ApplicationController
def index
#album = Album.find(params[:album_id])
#image = #album.images(params[:id])
#images = Image.all
end
def new
#album = Album.find(params[:album_id])
#image = #album.images.new
end
def create
#album = Album.find(params[:album_id])
#image = #album.images.build(params[:image])
if #image.save
flash[:notice] = "Successfully added image!"
redirect_to [:admin, :albums]
else
render :action => 'new'
end
end
def show
#album = Album.find(params[:id])
#image = #album.images(params[:id])
end
def destroy
#album = Album.find(params[:album_id])
#image = #album.images(params[:id])
#image.destroy
redirect_to admin_albums_path
end
end
View
<% #images.each do |image|%>
<%= image.title %> </br>
<%= image.description %> </br>
<%= image.image_name %> </br>
<%= button_to "Delete", admin_album_images_path(#album, image), :method => :delete, :style => "display: block; float: left;" %>
<%= debug #image %>
<% end %>
you should use
admin_album_image_path(#album, image)
note that both are singular. you can also change that to [:admin, #album, image] so you don't have to worry about the name of the route
An additional parameter will by default become the format so
admin_album_image_path(#album, image, :csv)
will be converted to
/admin/albums/1/images/1.csv
I am using the Nested_Set gem in my code to sort Categories, Subcategories, and Products. I am trying to limit the depth/level of my nested set to no deeper then 2. Currently I am getting the error
Nested Set Error undefined method `self_and_descendants' for #<ActiveRecord::Relation:0x52c4a30>
I am trying to create a restraunt menu type style, and am going to attempt to make it drag and drop sortable.
Here is my code:
Can someone browse it and help me understand this error? Thanks
Category.rb
class Category < ActiveRecord::Base
acts_as_nested_set
acts_as_list :scope => :parent_id
has_many :products
scope :category, where("parent_id IS NULL")
scope :subcategories, where("parent_id IS NOT NULL")
scope :with_depth_below, lambda { |level| where(self.arel_table[:depth].lt(level)) }
end
categories_controller
class CategoriesController < ApplicationController
def new
#category = params[:id] ? Category.find(params[:id]).children.new : Category.new
#count = Category.count
end
def new_subcategory
#category = params[:id] ? Category.find(params[:id]).children.new : Category.new
#category_2_deep = Category.with_depth_below(2)
end
def create
#category = params[:id] ? Category.find(params[:id]).children.new(params[:category]) : Category.new(params[:category])
if #category.save
redirect_to products_path, :notice => "Category created! Woo Hoo!"
else
render "new"
end
end
def edit
#category = Category.find(params[:id])
end
def edit_subcategory
#category = Category.find(params[:id])
#category_2deep = Category.with_depth_below(2).arrange
end
def destroy
#category = Category.find(params[:id])
#category.destroy
flash[:notice] = "Category has been obliterated!"
redirect_to products_path
end
def update
#category = Category.find(params[:id])
if #category.update_attributes(params[:category])
flash[:notice] = "Changed it for ya!"
redirect_to products_path
else
flash[:alert] = "Category has not been updated."
render :action => "edit"
end
end
def show
#category = Category.find(params[:id])
end
def index
end
def sort
params[:category].each_with_index do |id, index|
Category.update_all({position: index+1}, {id: id})
end
end
end
Routes.rb
Jensenlocksmithing::Application.routes.draw do
get "log_out" => "sessions#destroy", as: "log_out"
get "log_in" => "sessions#new", as: "log_in"
get "site/home"
get "site/about_us"
get "site/faq"
get "site/discounts"
get "site/services"
get "site/contact_us"
get "site/admin"
get "site/posts"
get "categories/new_subcategory"
get "categories/edit_subcategory"
resources :users
resources :sessions
resources :coupons
resources :monthly_posts
resources :categories do
collection { post :sort }
resources :children, :controller => :categories, :only => [:index, :new, :create, :new_subcategory]
end
resources :subcategories
resources :products
resources :reviews
resources :faqs do
collection { post :sort }
end
root to: 'site#home'
end
categories/form.html.erb
<%= form_for(#category) do |f| %>
<p>
<%= f.label(:name) %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label(:parent_id) %>
<%= f.select :parent_id, nested_set_options(#category_2_deep, #category) {|i, level| "# {'-' * level if level < 1 } #{i.name if level < 1 }" } %>
</p>
<p>
<%= f.label(:position) %>
<%= f.select :position, 1..category_count %>
</p>
<p>
<%= f.submit("Submit") %>
</p>
<% end %>
It looks like nested_set is looking for an Array not just an array-like collection - see line 32 of the source: https://github.com/skyeagle/nested_set/blob/21a009aec86911f5581147dd22de3c5d086355bb/lib/nested_set/helper.rb#L32
...hence it's getting that ActiveRecord::Relation, wrapping it in an [array] (line 35) and then trying to iterate and blowing up.
Easy fix: call to_a on the collection first - in your controller:
#category_2_deep = Category.with_depth_below(2).to_a
Better fix: submit a patch to the maintainer that's a bit more Ruby-like and looks for it to behave like an Array, but not necessarily be one.
I'm building an application that has a Keynote model and a Story model (as well as a User model that I implemented with Devise).
Keynotes have many Stories and a Story belongs to a Keynote.
I'm having problems creating new stories and I get the following error:
ActiveRecord::RecordNotFound in StoriesController#create
Couldn't find Keynote without an ID
The error happens on line 17 of stories_controller.rb which is
#keynote = Keynote.find(params[:keynote_id])
in the create method.
This is part of my stories_controller.rb
class StoriesController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
def index
#keynote = Keynote.find(params[:keynote_id])
#stories = #keynote.stories
end
def new
#keynote = Keynote.find(params[:keynote_id])
#story = #keynote.stories.build
end
def create
if user_signed_in?
#keynote = Keynote.find(params[:keynote_id])
#story = #keynote.current_user.stories.build(params[:story])
if #story.save
flash[:notice] = 'Question submission succeeded'
redirect_to keynote_stories_path
else
render :action => 'new'
end
end
end
This is my keynotes_controller.rb
class KeynotesController < ApplicationController
def index
#keynotes = Keynote.find :all, :order => 'id ASC'
end
def new
#keynote = Keynote.new
end
def show
#keynote = Keynote.find(params[:id])
end
def create
#keynote = Keynote.new(params[:keynote])
if #keynote.save
flash[:notice] = 'Keynote submission succeeded'
redirect_to keynotes_path
else
render :action => 'new'
end
end
end
Any help would be really appreciated.
Edit:
These are the Parameters when I try to create a new Story.
{"utf8"=>"✓",
"authenticity_token"=>"76odSpcfpTlnePxr+WBt36fVdiLD2z+Gnkxt/Eu1/TU=",
"story"=>{"name"=>"as"},
"commit"=>"Send"}
It looks like the ID for the Keynote is not being passed.
This is the view for StoriesController#new
<%= error_messages_for 'story' %>
<%= form_for #story do |f| %>
<p>
Question:<br />
<%= f.text_field :name %>
</p>
<p>
<%= submit_tag "Ask" %>
</p>
<% end %>
This is what I have in my routes.rb file:
get "keynotes/index"
get "users/show"
devise_for :users
get "votes/create"
get "stories/index"
resources :keynotes do
resources :stories
end
resources :stories do
get 'bin', :on => :collection
resources :votes
end
resources :users
root :to => 'keynotes#index'
I think this should do the trick:
<%= form_for #story do |f| %>
<%= hidden_field_tag 'keynote_id', #keynote.id %>
.
rest of the form stuff here
.
<% end %>
PS. Not sure if you will get the keynote_id in params[:keynote_id] or params[:story][:keynote_id] .. check out both.
NB: I think there would be a easier way to do it too, using fields_for or something similar, but I don't have access to a Rails setup at the moment to test that out.
I'm using acts_as_taggable_on v.2.0.3 in Rails 3 to add tags to posts. I add a tag cloud as described here: https://github.com/mbleigh/acts-as-taggable-on, but I'm encountered an error:
ActionController::RoutingError in Posts#index: No route matches {:action=>"tag", :id=>"politics", :controller=>"posts"}. My code is below:
PostHelper:
module PostsHelper
include TagsHelper
end
Model Post:
class Post < ActiveRecord::Base
...
acts_as_taggable_on :tags
end
PostController
class PostController < ApplicationController
...
def tag_cloud
#tags = Post.tag_counts_on(:tags)
end
end
View:
<% tag_cloud(#tags, %w(css1 css2 css3 css4)) do |tag, css_class| %>
<%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>
<% end %>
Routes.rb:
Blog::Application.routes.draw do
root :to => "posts#index"
resources :posts do
member do
post :notify_friend
end
collection do
get :search
end
resources :comments
end
resources :users
resource :session
match '/login' => "sessions#new", :as => "login"
match '/logout' => "sessions#destroy", :as => "logout"
end
What am i doing wrong? Thanks for your answers.
Hmm, i think i understand.
First, i edited routes.rb in a such way:
resources :posts do
...
collection do
get :tag
end
end
Second, i added method "Tag" in the PostController:
def tag
#posts = Post.tagged_with(params[:id])
#tags = Post.tag_counts_on(:tags)
render :action => 'index'
end
It works!
For Rails4 #muki_rails approach did not work. This is what I did:
In routes.rb:
get 'tags/:tag' => 'articles#index', as: 'tag'
Now I can do this in the view (I am using slim):
- #article.tags.each do |tag|
= link_to tag.name, tag_path(tag.name)
Then in my ArticlesController if the params[:tag] variable is set, I search for all corresponding articles that match the given task.
def index
if params[:tag].present?
#articles = Article.published.tagged_with(params[:tag])
else
#articles = Article.published
end
end