I know this is the most commonly asked question but i am really looking for some help here as i don't understand what i am doing wrong here .
I have a generated a devise user and intend to create a gallery for users . Following is the code i have tried
Model - Gallery.rb
class Gallery < ActiveRecord::Base
belongs_to :user
end
Controller - galleries_controller.rb
class GalleriesController < ApplicationController
before_action :set_gallery, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!
respond_to :html
def index
#user = User.find(params[:user_id])
#galleries = Gallery.all
respond_with(#galleries)
end
def show
respond_with(#gallery)
end
def new
#user = User.find(params[:user_id])
#gallery = Gallery.new
respond_with(#gallery)
end
def edit
end
def create
#gallery = Gallery.new(gallery_params)
flash[:notice] = 'Gallery was successfully created.' if #gallery.save
respond_with(#gallery)
end
def update
flash[:notice] = 'Gallery was successfully updated.' if #gallery.update(gallery_params)
respond_with(#gallery)
end
def destroy
#gallery.destroy
respond_with(#gallery)
end
private
def set_gallery
#gallery = Gallery.find(params[:id])
end
def gallery_params
params[:gallery, :user_id]
end
end
Folowing is the error that gets shown with better errors -
Logs
Started GET "/galleries/1" for 127.0.0.1 at 2015-05-03 15:24:10 +0530
Processing by GalleriesController#show as HTML
Parameters: {"id"=>"1"}
Gallery Load (2.1ms) SELECT "galleries".* FROM "galleries" WHERE "galleries"."id" = ? LIMIT 1 [["id", 1]]
Completed 404 Not Found in 63ms
ActiveRecord::RecordNotFound - Couldn't find Gallery with 'id'=1:
activerecord (4.2.0) lib/active_record/core.rb:154:in `find'
routes.rb
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users do
resources :galleries
resources :photos
end
end
As i am still new to ROR , any help would be very much appreciated . Thanks in advance .
From the URL i am assuming you are not passing user_id in params.
In your route file gallery should be nested route. If you wan't user_id.
resources :users do
resources :galleries do
end
end
or you can use
#user= current_user
Related
I'm currently creating a website that would allow a visitor to read a magazine online. I created a scaffold for the magazine itself, and another one for the pages, which belongs to the magazine. This way, I can create a multi upload for the pages while creating the magazine, and everything gets uploaded in the same time.
When I nest the pages resources inside the magazine's resources, as following:
resources :magazines do
resources :pages
end
I get "domain.com/magazines/<slug>/pages/id"
However, I had some issues with the id, because it can't be used to count the pages (since the id never goes back to 1), so I created a function inside the controller that would count the pages for me, and save each pages with a "page_number" value.
My question is the following: how, instead of the id, can I kindly ask my router to use the :page_number ?
I tried to create a custom route, which looked like this
resources :magazines do
get '/:page_number' => 'pages#show', as: :custom_page
end
But for an unknown reason, Rails tells me that my custom route simply doesn't exist, even though it exists when I type rake routes
Thank you in advance
Edit
Here is my magazine_controller.rb
class MagazinesController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update, :destroy]
before_action :set_magazine, only: [:show, :edit, :update, :destroy]
def index
#magazines = Magazine.all
end
def show
end
def new
#magazine = Magazine.new
end
def edit
end
def create
#magazine = Magazine.new(magazine_params)
if #magazine.save
if params[:images]
(params[:image] || []).each_with_index do |image, index|
#magazine.pages.create(image: image, page_number: index + 1)
end
redirect_to #magazine, notice: 'Magazine was successfully created.'
else
render :new
end
end
end
def update
if #magazine.update(magazine_params)
if params[:images]
params[:images].each { |image|
#magazine.pages.create(image: image)
}
end
redirect_to #magazine, notice: 'Magazine was successfully updated.'
else
render :edit
end
end
def destroy
#magazine.destroy
redirect_to magazines_url, notice: 'Magazine was successfully destroyed.'
end
private
def set_magazine
#magazine = Magazine.friendly.find(params[:id])
end
def magazine_params
params.require(:magazine).permit(:titre, :apercu)
end
end
and here is page_controller.rb
class PagesController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update, :destroy]
before_action :set_page, only: [:show, :edit, :update, :destroy]
def index
#pages = Page.all
end
def show
end
def new
#page = Page.new
end
def edit
end
def create
#page = Page.new(page_params)
if #page.save
redirect_to #page, notice: 'Page was successfully created.'
else
render :new
end
end
def update
if #page.update(page_params)
redirect_to #page, notice: 'Page was successfully updated.'
else
render :edit
end
end
def destroy
#page.destroy
redirect_to :back, notice: 'Page was successfully destroyed.'
end
private
def set_page
#page = Page.find(params[:id])
end
def page_params
params.require(:page).permit(:titre, :apercu)
end
end
Edit 2
Here is the output from development.log when trying to reach the page
Started GET "/magazines/magazine-54/pages/11" for 127.0.0.1 at 2016-12-12 11:04:45 +0100
Processing by PagesController#show as HTML
Parameters: {"magazine_id"=>"magazine-54", "id"=>"11"}
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.0ms)
NoMethodError (undefined method `pages' for nil:NilClass):
app/controllers/pages_controller.rb:49:in `set_page'
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (2.4ms)
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.2ms)
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.7ms)
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (13.8ms)
With these routes
resources :magazines do
resources :pages
end
you should be able to update PagesController and add/update following methods:
def magazine
#magazine = Magazine.find(params[:magazine_id])
end
def page
#page = #magazine.pages.find_by(page_number: params[:id])
end
to make it work you should have page_number column in Page model and has_many :pages association in Magazine model
I have been looking at other people's posts about this question. Unfortunately, still a while later I am stuck on it. I understand that a couple of the controller methods cannot find a story with the relevant 'ID' and render that to the views, hence my error.
However, I don't understand how I can edit my controller methods/routing so it can actually find the id of '1,2,3,4 etc'. I believe it is trying to look for a different from of ID. The 'create' and 'show' methods are creating the same error.
Error on screen:
ActiveRecord::RecordNotFound in StoriesController#create
Couldn't find Story with 'id'=
def find_story
#story = Story.find(params[:id])
end
Here, I have put in ID as the params for the story find method but it isn't finding it. Why?
class StoriesController < ApplicationController
before_action :find_story, only: [:destroy, :create, :show, :edit, :update]
def index
#stories = Story.order('created_at DESC')
end
def new
#story = Story.new
end
def create
#story = Story.new(story_params)
if #story.save
flash[:success] = "Your beautiful story has been added!"
redirect_to root_path
else
render 'new'
end
end
def edit
end
def update
if #story.update.attributes(story_params)
flash[:success] = "More knowledge, more wisdom"
redirect_to root_path
else
render 'edit'
end
end
def destroy
if #story.destroy
flash[:success] = "I think you should have more confidence in your storytelling"
else
flash[:error] = "Can't delete this story, sorry"
end
end
def show
#stories = Story.all
end
private
def story_params
params.require(:story).permit(:name, :description)
end
def find_story
#story = Story.find(params[:id])
end
end
My routes.rb:
Rails.application.routes.draw do
get 'stories/new/:id' => 'posts#show'
resources :stories
devise_for :users
root to: 'stories#index'
end
You want to change the ":find_story" to not include the create as that is what is telling it to look for an id, but there is no id when on the create page, you are creating a new one, not finding one that exists
so change the before_action to this
before_action :find_story, only: [:destroy, :show, :edit, :update]
Your issue with stories is the route you are trying to use. Show looks for an id, for the same reason I mentioned above, so the route need to be something like
stories/show/1
where "1" is the id of the story you want.
ActiveRecord::RecordNotFound in StoriesController#create
you have before_action :find_story with create method which is trying to find Story but there is no :id in params
So you need to remove :create action from the list of before_action and change it to
before_action :find_story, only: [:destroy, :show, :edit, :update]
I have got the same problem.
#table = Table.find(params[:id])
ActiveRecord::RecordNotFound - Couldn't find Table with 'id'=12222:
app/controllers/tables_controller.rb:27:in `edit'
Sol: Try this query
#table = Table.find_by_id(params[:id])
I am a beginner to Ruby on Rails and this is an ruby on rails that was developed by someone.
There are 2 types of users: registered user with "user" role and registered user with "admin" role.
This too many redirects only happens if the user's role = "user", but not so if the user is "admin". I haven't figure out why yet.
First, if the user is the admin, I will get this in the log:
Started GET "/" for ::1 at 2016-07-22 18:18:17 -0700
Processing by ProductsController#home as HTML
^[[1m^[[35mUser Load (0.1ms)^[[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 11]]
controller_path: products
resource: product
method: product_params
after the parms setting => ${params}
Debugging in the Ability.rb...
User: #<User:0x007fe6d7f0f670>
user is admin
^[[1m^[[36mProduct Load (0.3ms)^[[0m ^[[1mSELECT "products".* FROM "products"^[[0m
^[[1m^[[35mVersion Load (1.1ms)^[[0m SELECT "versions".* FROM "versions"
^[[1m^[[36mReltype Load (1.0ms)^[[0m ^[[1mSELECT "reltypes".* FROM "reltypes"^[[0m
and many more SQL statements; I would love to simplify that but that is a different question and another learning opportunity.
If the user is a regular user, the "redirect" will happen right after user is regular user
Started GET "/" for ::1 at 2016-07-22 18:25:23 -0700
Processing by ProductsController#home as HTML
^[[1m^[[36mUser Load (0.1ms)^[[0m ^[[1mSELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1^[[0m [["id", 11]]
controller_path: products
resource: product
method: product_params
after the parms setting => ${params}
Debugging in the Ability.rb...
User: #<User:0x007fe6d13dca88>
user is regular user
Redirected to http://localhost:3000/
Completed 302 Found in 6ms (ActiveRecord: 0.1ms)
Started GET "/" for ::1 at 2016-07-22 18:25:23 -0700
Processing by ProductsController#home as HTML
^[[1m^[[35mUser Load (0.1ms)^[[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 11]]
controller_path: products
resource: product
method: product_params
...repeat... for many more
My guess is that the landing page is trying to pull all the data for use in this page and each SQL triggers a redirect... But first, I like to find why does it make a difference between an user with role user vs. role admin. I will worry about optimization later. Any help will be much appreciated.
Here is the config/routes.rb
Rails.application.routes.draw do
resources :groupings
resources :platforms
resources :versions
resources :reltypes
resources :products
# Devise stuff
devise_for :users
devise_scope :user do
get '/login' => 'devise/sessions#new'
get '/logout' => 'devise/sessions#destroy'
end
resources :users, :controller => "users"
unauthenticated :user do
resources :products, only: [:index, :show]
resources :versions, only: [:index, :show]
resources :reltypes, only: [:index, :show]
resources :platforms, only: [:index, :show]
resources :groupings, only: [:index, :show]
end
# You can have the root of your site routed with "root"
root to: 'products#home'
namespace :api, :defaults => {:format => :json} do
resources :platforms
resources :versions
resources :reltypes
resources :products
resources :groupings
end
end
Next, controllers/application.rb
class ApplicationController < ActionController::Base
# include DeviseTokenAuth::Concerns::SetUserByToken
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
# Devise: redirect to login page if user not logged in
before_action :authenticate_user!
before_filter do
resource = controller_path.singularize.to_sym
method = "#{resource}_params"
Rails.logger.debug("controller_path: #{controller_path}")
Rails.logger.debug("resource: #{resource}")
Rails.logger.debug("method: #{method}")
params[resource] &&= send(method) if respond_to?(method, true)
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, :password, :password_confirmation, roles: [])}
end
# CanCan: if user authorization fails, catch and modify
check_authorization :unless => :devise_controller?
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
end
Here is the models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
before_save :default_values
def default_values
# self.role ||= 'user'
self.role = "user"
end
def is?(requested_role)
self.role == requested_role
end
end
Finally, I found this models/activity.rb (I tried to put some debugging statements here:
class Ability
include CanCan::Ability
def initialize(user)
# Define abilities for the passed in user here. For example:
#
user ||= User.new # guest user (not logged in)
Rails.logger.debug("Debugging in the Ability.rb...")
Rails.logger.debug("User: #{user}")
if user.is? "admin"
Rails.logger.debug("user is admin")
can :manage, :all
else
Rails.logger.debug("user is regular user")
can :read, :all
end
end
end
Added the controllers/products_controller.rb (as suggested by Sri Vishnu Totakura). I skipped the code for update/destroy just to save a little space.
class ProductsController < ApplicationController
load_and_authorize_resource #for CanCan
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
end
def home
#products = Product.all
#versions = Version.all
#platforms = Platform.all
#reltypes = Reltype.all
#prevrels = Prevrel.all
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
# puts "params for new: "
# puts params
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
puts "params for create: "
puts params
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
...
end
def destroy
...
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
#versions = #product.versions
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:name)
end
end
It seems that the problem is here:
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
For some reason when you're not an admin, that exception is raised, and you fall into a loop, as you redirect to ProductsController#home which is the root to: 'products#home'
I don't see your products controller code, but the problem should be there. Let me know.
Since I can not comment or upvote Paulo 's answer I am leaving this here for everyone having a similar problem.
His answer made me take a better look in my controller that was causing the infinite redirects and particularly the action that was triggered and eventually solve this.
I was using devise/cancancan as well.
Specifically, I had a companies_controller.rb.
Furthermore, in a before_action I had something like the following
before_action :set_company, only: :show
and the set_company action was this
def set_company
...
authorize! params[:action].to_sym, #company || Company
end
As soon as I removed the authorize! call the redirect loop stopped.
I haven't figured what caused the loop, since my user roles seemed just fine, but this was definitely the cause.
I'm building an app which consists on sharing résumés. I am using Devise gem. Each user is able to create only one résumé. I made the models and and their relations. Resume belongs_to User and User has_one 'Resume'.
After making the views, I wanted to test my app but I got the error: undefined methodbuild' for nil:NilClass`
Here is my ResumeController and my routes.rb
class ResumeController < ApplicationController
before_action :find_resume, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
def show
# #resume = Resume.find_by(params[:id])
end
def new
#resume = current_user.resume.build
end
def create
#resume = current_user.resume.build(resume_params)
if #resume.save
redirect_to #resume, notice: "resume was successfully created"
else
render 'new'
end
end
def edit
end
def update
if #resume.update(pin_params)
redirect_to #resume, notice: "resume was successfully updated"
else
render 'edit'
end
end
def destroy
#resume.destroy
redirect_to root_path
end
private
def resume_params
params.require(:resume).permit(:title, :description)
end
def find_resume
#resume = resume.find(params[:id])
end
end
Routes.rb
Rails.application.routes.draw do
devise_for :users
resources :resume, except: [:index]
get 'static_pages/index'
root to: "static_pages#index"
end
I just want the user to be able to create only one Resume and then he will be able to share it.
Update: After following messanjah's answer there was another error coming from the _form.html.erb: undefined method resumes_path' for #<#<Class:0x00...>. Here is the gist with forms and model: goo.gl/XvW2LH So you can see all the files closely.
Without more knowledge of where the error is happening, I can only suggest some areas that might be suspect.
To build a has_one relationship, you must use the build_*association* constructor.
def new
#resume = current_user.build_resume
end
def create
#resume = current_user.build_resume(resume_params)
end
In my rails app, a Timesheet has_many Entries and an Entry belongs_to a Timesheet.
class Timesheet < ActiveRecord::Base
has_many :entries, order: 'position', dependent: :destroy
end
class Entry < ActiveRecord::Base
belongs_to :timesheet
end
I'm following Railscast 147 for sortable lists (the updated version). In the development log I notice that my params hash correctly updates the sort order, but on reload it doesn't save the positions correctly. Furthermore, the request is being processed by the create action instead of my custom sort action. Here's my controller.
class EntriesController < ApplicationController
before_filter :signed_in_user
before_filter :find_timesheet
def index
#entries = #timesheet.entries.order("position")
#entry = #timesheet.entries.build
end
def create
#entry = #timesheet.entries.build(params[:entry])
#entry.position = #timesheet.entries.count + 1
if #entry.save
#flash[:notice] = "Entry created"
#redirect_to timesheet_entries_path
respond_to do |format|
format.html { redirect_to timesheet_entries_path }
format.js
end
else
flash[:alert] = "Entry could not be added"
render 'new'
end
end
def destroy
#entry = #timesheet.entries.find(params[:id])
#entry.destroy
respond_to do |format|
format.html { redirect_to timesheet_entries_path, flash[:notice] = "Entry destroyed" }
format.js
end
end
def sort
params[:entry].each_with_index do |id, index|
#timesheet.entries.update_all({position: index+1}, {id: id})
end
render nothing: true
end
private
def find_timesheet
#timesheet = Timesheet.find(params[:timesheet_id])
end
end
and my routes.rb file.
Sledsheet::Application.routes.draw do
resources :timesheets do
resources :entries, only: [:index, :create, :destroy] do
collection { post :sort }
end
end
end
The entries.js.coffee
jQuery ->
$("#entries tbody").sortable(
helper: fixHelper
update: ->
$.post($(this).data('update-url'), $(this).sortable('serialize'))
).disableSelection()
The output from the development log
Started POST "/timesheets/8/entries" for 127.0.0.1 at 2012-06-04 20:14:18 -0400
Processing by EntriesController#create as */*
Parameters: {"entry"=>["60", "59", "61"], "timesheet_id"=>"8"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'qDs53hgOWfRMbNN9JKau3w' LIMIT 1
Timesheet Load (0.1ms) SELECT "timesheets".* FROM "timesheets" WHERE "timesheets"."id" = ? ORDER BY date DESC LIMIT 1 [["id", "8"]]
Completed 500 Internal Server Error in 2ms
NoMethodError (undefined method `stringify_keys' for "60":String):
app/controllers/entries_controller.rb:11:in `create'
I googled the error about the undefined method, but I'm confused why the create action would be called in this case anyway? I do have a new_entry form on the page, that creates a new entry via Ajax. Perhaps this is interfering with the sort? Any help would be appreciated!
The reason why there's no 'stringify_keys' method is because you're passing an array to the create action and not the sort action.
What do you have for data-update-url in your erb.html file?
Should be sort_entries_path.