I'm getting this error of ApplicationBaseController where it is throwing up a name error. Is there anything wrong in both of these codes because ruby is throwing errors even though i'm inheriting from the applicationbasecontroller in the application controller
class ShoppingController < ApplicationController
def index
#categories = Category.all()
end
def new
end
def showcollection
#products =Product.where(category_id: params[:id])
#productcount = Product.where(category_id: params[:id]).count
end
def create_product
#product = Product.new(product_params)
if (#product.save())
redirect_to shopping_index_path
else
render 'new'
end
end
private def product_params
params.require(:product).permit(:name,:price, :category_id, :image)
end
end
class ApplicationController < ActionController::Base
end
Also here is my directory structure
enter image description here
Related
To have a cleaner code I want to split my controller in some concerns.
In my routes.rb how to redirect to concern without redefine the methods of concern index show destroy create ...
class SomeController
include SomeConcern
def index
end
end
module SomeConcern
def index
end
end
Sorry for my bad english.
Lets say we have a CarsController and AirplanesController that have the typical create and new actions.
class AirplanesController < ApplicationController
def new
#airplane = Airplane.new
end
def create
#airplane = Airplane.new(create_params)
if #airplane.save
redirect_to #airplane
else
render :new
end
end
# ...
end
class CarsController < ApplicationController
def new
#car = Car.new
end
def create
#car = Car.new(create_params)
if #car.save
redirect_to #car
else
render :new
end
end
# ...
end
To dry this up we can extract the shared code to a module:
module Createable
extend ActiveSupport::Concern
included do
attr_accessor :resource
alias_attribute :self.controller_name.to_sym, :resource
end
def new
#resource = resource_class.new
yield #resource if block_given?
end
def create
#resource = resource_class.new(create_params)
if #resource.save
yield #resource if block_given?
redirect_to #resource
else
render :new
end
end
private
def create_params
raise "not implemented controller!"
end
def resource_class
#resource_class ||= self.controller_name.classify.constantize
end
end
We can then apply it to the controller classes by:
class CarsController < ApplicationController
include Createable
def create_params
params.require(:car)
.permit(:model) # ...
end
end
class AirplanesController < ApplicationController
include Createable
def create_params
params.require(:airplane)
.permit(:model) # ...
end
end
But a very important point here is that you are not routing to the module. The module is providing methods to the controller class.
You have to always map to your controller. Concerns are modules where you can put shared logic (it makes sense only in case you need 2 absolutely similar methods in 2 different controllers).
I think, that such code should work:
class SomeController
include SomeConcern
end
module SomeConcern
def index
end
end
Isn't it?
But concerns mostly used to move out some private helper methods from controller, rather actions as we do in this code piece
I use Rails 4, and have four methods at my application_controller.rb for setting flash messages in Rails
def exclusion_info_for model_name
flash[:notice] = "#{model_name.to_s.capitalize} has been deleted."
end
def creation_notice_for model_name
flash[:notice] = "#{model_name.to_s.capitalize} has been created."
end
def update_notice_for model_name
flash[:notice] = "#{model_name.to_s.capitalize} has been updated."
end
def error_notice
flash[:error] = "An unexpected error has it occurred"
end
But the flash setting at exclusion_notice_for is lost after redirection of the action destroy. The others methods works normally.
The Controller
class CustomersController < ApplicationController
respond_to :html
def new
respond_with #customer = customer
end
def create
if #customer = Customer.create(customer_attrs)
creation_notice_for :customer
else
error_notice
end
respond_with #customer, location: "/"
end
def show
respond_with #customer = customer
end
def index
respond_with #customers = Customer.all
end
def edit
respond_with #customer = customer
end
def update
if #customer = customer.update(customer_attrs)
update_notice_for :customer
else
error_notice
end
respond_with #customer, location: "/"
end
def destroy
if #customer = customer.destroy()
exclusion_info_for :customer
else
error_notice
end
respond_with #customer, location: "/"
end
private
def customer
id ? Customer.find(id) : Customer.new
end
def customer_attrs
params.require(:customer).permit(:name)
end
end
This is the application destroy button currently genereted
This is the application.rb file
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :null_session
# protect_from_forgery with: :exception
include FormattedTime
def form_parent
ObjectSpace._id2ref(params[:form_parent_object_id].to_i) if params[:form_parent_object_id]
end
helper_method :form_parent
def root
render "layouts/application", layout: false
end
protected
def id
params[:id]
end
# refactored
def info_flashed model_name, action
flash[:notice] = "#{model_name.to_s.capitalize} has been #{action}."
end
def error_notice
flash[:error] = "An unexpected error has it occurred"
end
end
Flashing Method will work all of your actions simply add 'created' or 'updated' string like in destroy method.
You had error Can't verify CSRF token authenticity
You can put this method in application.rb file to fix it all.
protect_from_forgery with: :exception, if: Proc.new { |c| c.request.format != 'application/json' }
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
protected
def info_flashed (model_name, action)
flash[:notice] = "#{model_name.to_s.capitalize} has been #{action}."
end
In Controller
def destroy
if #customer = customer.destroy
info_flashed (#customer, 'deleted')
else
error_notice
end
respond_with #customer, location: "/" # you need to redirect correct path.
end
I am building an application that allows users to create a trip. However, for some reason I am not sure if I am truly utilizing the power of rails or am I being redundant in my code. In the following example you will see a trip controller where a trip can be created and then displayed. Everything works, I just want to make sure I am going about it in the most minimal fashion.
class TripsController < ApplicationController
def new
#user = User.find(session[:id])
#trip = Trip.new
end
def create
#trip = Trip.create(trip_params)
#user = User.find(session[:id])
redirect_to user_trip_path(#user.id, #trip.id)
end
def show
#trip = Trip.find(params[:id])
end
private
def trip_params
params.require(:trip).permit(:where, :when, :price_per_person)
end
end
To tighten it up, "scope the trip to the user".
class TripsController < ApplicationController
before_filter :find_user
def new
#trip = #user.trips.build #assuming a User has many trips
end
def create
#trip = #user.trips.create(trip_params) #you may want to add an if else here to catch bad trips
redirect_to user_trip_path(#user.id, #trip.id)
end
def show
#trip = #user.trips.find(params[:id])
end
private
def trip_params
params.require(:trip).permit(:where, :when, :price_per_person)
end
def find_user
#user = User.find(session[:id]) # or current_user if you are using popular authentication gems
end
end
It's about readability too, not just less lines.
I have a method in my Rails application controller that I call when I am creating a new Post. I have also created an API to create a new Post. However, it seems that I need to repeat the code for my application controller method in my API BaseController. Where is the best place to put the application controller method in my Rails app so that I do not have to repeat the code for the API? Is there a way that the API base controller can inherit from the ApplicationController?
Rails app
class PostsController < ApplicationController
def create
#post = Post.new(post_params)
#post.text = foo_action(#post.text)
if #post.save
redirect_to posts_path
else
render :new
end
end
end
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def foo_action(string)
return string
end
end
Rails API
class Api::V1::PostsController < Api::V1::BaseController
def create
#post = Post.new(post_params)
#post.text = foo_action(#post.text)
if #post.save
respond_with(#post)
end
end
end
class Api::V1::BaseController < ActionController::Base
respond_to :json
def foo_action(string)
return string
end
end
Based on #phoet's recommendation in the comments above, I moved the foo_action method to the Post model:
class Post < ActiveRecord::Base
def foo_action
string = self.text
return string
end
end
class PostsController < ApplicationController
def create
#post = Post.new(post_params)
#post.text = #post.foo_action
if #post.save
redirect_to posts_path
else
render :new
end
end
end
class Api::V1::PostsController < Api::V1::BaseController
def create
#post = Post.new(post_params)
#post.text = #post.foo_action
if #post.save
respond_with(#post)
end
end
end
Say I have the following controller:
class FooController < ApplicationController
def show
end
def a
foo = Foo.find(params[:id])
foo.a
redirect_to foo_url(foo)
end
def b
foo = Foo.find(params[:id])
foo.b
redirect_to foo_url(foo)
end
def c
foo = Foo.find(params[:id])
foo.c
redirect_to foo_url(foo)
end
end
Is there anyway to get a after_filter to perform the shared redirect code?
Try this:
class FooController < ApplicationController
def show
end
[:a, :b, :c].each do |name|
define_method(name) do
foo = Foo.find(params[:id])
foo.send(:name)
redirect_to foo_url(foo)
end
end
end
An after_filter will not work in this situation.
I would use the following approach.
class FooController < ApplicationController
before_filter :get_foo, :only => [:a, :b, :c]
def show
end
def a
do_and_redirect(:a)
end
def b
do_and_redirect(:b)
end
def c
do_and_redirect(:c)
end
private
def get_foo
#foo = Foo.find(params[:id])
end
def do_and_redirect(method_name)
#foo.send(method_name)
redirect_to foo_url(#foo)
end
end
Here's your code refactored:
class FooController < ApplicationController
before_filter :get_foo, :except => [:show]
def show
end
def a
#foo.a
redirect_to #foo
end
def b
#foo.b
redirect_to #foo
end
def c
#foo.c
redirect_to #foo
end
private
def get_foo
#foo = Foo.find(params[:id])
end
end
I haven't tried it, but http://rails.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html#M000319 says you can use the after_filter.
Leave it where it is. after_filters won't work in this case.