I'm looking at this code, I can see that is says actions: show and index but where are the methods show and index??
http://github.com/railsdog/spree/blob/master/core/app/controllers/products_controller.rb
class ProductsController < Spree::BaseController
HTTP_REFERER_REGEXP = /^https?:\/\/[^\/]+\/t\/([a-z0-9\-\/]+\/)$/
#prepend_before_filter :reject_unknown_object, :only => [:show]
before_filter :load_data, :only => :show
resource_controller
helper :taxons
actions :show, :index
private
def load_data
load_object
#variants = Variant.active.find_all_by_product_id(#product.id,
:include => [:option_values, :images])
#product_properties = ProductProperty.find_all_by_product_id(#product.id,
:include => [:property])
#selected_variant = #variants.detect { |v| v.available? }
referer = request.env['HTTP_REFERER']
if referer && referer.match(HTTP_REFERER_REGEXP)
#taxon = Taxon.find_by_permalink($1)
end
end
def collection
#searcher = Spree::Config.searcher_class.new(params)
#products = #searcher.retrieve_products
end
def accurate_title
#product ? #product.name : nil
end
end
My guess is that the actions method is loaded with resource_controller as a module from the lib directory. Then calling the actions method creates the index and show methods.
The class inherits from Spree::BaseController and ActionController. Spree::BaseController has method action which takes method names as messages.
Related
Well im going to clarify im doing it
class DuplicatesController < ApplicationController
before_action :set_venue, only: [:new]
def new
end
def create
if #venue.duplicate(venue_params)
flash[:success] = t('controller.create.success',
resource: Venue.model_name.human)
redirect_to admin_venue_url #venue
else
flash[:warning] = #venue.errors.full_messages.to_sentence
render :new
end
end
private
def set_venue
#venue = Venue.friendly.find params[:venue_id]
end
end
def venue_params
params.require(:venue).permit(:name,
:address,
:address_complement,
:city,
:phone)
end
end
def duplicate
(name,
address,
address_complement,
city,
phone)
new_venue = self.dup
new_venue.update_attributes(description: self.description,
logo: self.logo,
opening_time: self.opening_time,
closing_time: self.closing_time,
ally_id: self.ally_id)
new_venue.save
end
How can I call those params in my duplicates controller, thanks
I need to set the attributes, after create a dup because I want to save a new record with new information, but i dont know to do it in my method, someone could explain me
Thanks.
Probably the best way to do it is to pass only id/slug of original model.
Then your duplicates_controller.rb can look similar to this:
class DuplicatesController < ApplicationController
def create
old_venue = Venue.friendly.find(params[:id])
venue = old_venue.dup
venue.attributes = venue_params
if venue.save
# success render
else
# error render
end
end
private
def venue_params
params.require(:venue).permit(:permitted_attributes) # id should not be there
end
end
Of course you can refactor it, but I do not think it is needed in this situation.
Or my favourite is to change VenueController#create to something like this to allow creating from another instance:
if copy_from_id = params[:copy_from_id]
#copy_source = Venue.find_by(id: copy_from_id)
#venue = #copy_source.dup
#venue.attributes = venue_params
else
#venue = Venue.new
end
if #resource.save
...
else
...
end
I created a polymorphic relation in a book reviewing app that I am writing. My app has the nested models: Piece >> Section >> Subsection >> Subsubsection, and I have created a model which belongs to all of these called KeyConcept, my intention being that each of these can have a key concept.
I am getting an error that I don't understand when trying to display the index action of the keyconcepts controller.
I think it might be due to a naming conflict but I don't have enough experience to understand it.
the error I am getting looks like this:
Unable to autoload constant KeyConceptsController, expected /home/david/Documents/Learning/StuddyBuddy/app/controllers/key_concepts_controller.rb to define it
else
require_or_load(expanded, qualified_name)
raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
return from_mod.const_get(const_name)
end
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
My keyconcepts controller looks like this:
key_concepts_controller.rb
class Key_conceptsController < ApplicationController
include KeyconceptsHelper
def whereami
if params[:piece_id]
#piece = Piece.find(params[:piece_id])
#keyconcept = #piece.key_concepts.find(params[:id])
here = #piece
parameter = :piece_id
type = "Piece"
elsif params[:section_id]
#section = Section.find(params[:section_id])
#piece = #section.piece_id
#keyconcept = #section.key_concepts.find(params[:id])
here = #section
parameter = :section_id
type = "Section"
elsif params[:subsection_id]
#subsection = Subsection.find(params[:subsection_id])
#section = #subsection.section_id
#piece = Section.find(id=#section).piece_id
here = #subsection
parameter = :subsection_id
type = "Subsection"
elsif params[:subsubsection_id]
#subsubsection = Subsubsection.find(params[:subsubsection_id])
#subsection = #subsubsection.subsection_id
#section = Subsection.find(id=#subsection).section_id
#piece = Section.find(id=#section).piece_id
here = #subsubsection
parameter = :subsubsection_id
type = "Subsubsection"
end
end
def redirect
if type == "Piece"
#redirect = redirect_to piece_path(#piece)
elsif type == "Section"
#redirect = redirect_to piece_section_path(#piece, #section)
elsif type == "Subsection"
#redirect = redirect_to piece_section_subsection_path(#piece, #section, #subsection)
elsif type == "Subsubsection"
#redirect = redirect_to piece_section_subsection_subsubsection_path(#piece, #section, #subsection, #subsubsection)
end
end
def index
whereami.call
#piece = Piece.find(params[:piece_id])
#keyconcept = #piece.key_concepts.find(params[:id])
#redirect = redirect.call
end
def show
whereami.call
redirect.call
end
def new
#keyconcept = KeyConcept.new
#keyconcept.conceptable_id = here.id
end
def create
whereami.call
#keyconcept = KeyConcept.new(keyconcept_params)
#keyconcept.conceptable_id = params[parameter]
#keyconcept.conceptable_type = type
#keyconcept.save
redirect.call
end
def destroy
here.destroy
redirect.call
flash.notice = "#{type} '#{here.name}' from '#{#piece.name}' deleted!"
end
def edit
whereami.call
end
def update
whereami.call
here.update(keyconcept_params)
flash.notice = "#{type} '#{here.name}' Updated!"
redirect.call
end
end
the link comes from the show action of the parent Piece model here:
<% #piece.key_concepts.each do |concept| %>
<li>
<%= link_to concept.definition, [#piece, #keyconcept] %>
<!-- we didn't use #piece_key_concept_path(#piece, #keyconcept), class: 'section_name' and it worked -->
</li>
How do I link to the keyconcepts "show" action by the way? I havent been able to so i just linked to the index action :/
So the routes.rb file looks like this:
resources :pieces do
resources :sections do
resources :subsections do
resources :subsubsections
end
end
resources :links
end
resources :pieces, :sections, :subsections, :subsubsections do
resources :connections, only: [:index, :new, :edit, :update, :destroy, :create]
resources :keyconcepts, only: [:index, :new, :edit, :update, :destroy, :create, :show]
end
key_concept.rb
class KeyConcept < ActiveRecord::Base
belongs_to :conceptable, polymorphic: true
end
piece.rb
class Piece < ActiveRecord::Base
include Connectable
include Conceptable
has_many :sections
has_many :subsections, through: :sections
has_many :links
end
in models/concerns/conceptable.rb
module Conceptable
extend ActiveSupport::Concern
included do
has_many :keyconcepts, as: :conceptable
end
end
Well the problem is naming convention
Your key_concepts_controller class name should be
KeyConceptsController < ApplicationController
Also make sure you follow proper conventions
If your model name is KeyConcept file name must be key_concept.rb
Controller name should be KeyConceptsController and file name must be key_concepts_controller.rb
Same goes with routes
resources : key_concepts
Refer this for more details
i have class HomeController
class HomeController < ApplicationController
def event_one
Req = **endpoint.connection**
res = req.body**(json format)**
#events = res
end
def event_two
#events
end
end
Can i use one instance variable(#events) which got response from endpoint in event_one method,from another event_two method.
try using this DRY code:
class HomeController < ApplicationController
before_action :set_events, only: [:event_one, :event_two]
def event_one
#your code here
# for example puts #events
end
def event_two
#your code here
# for example puts #events
end
private
def set_events
req = **endpoint.connection**
res = req.body**(json format)**
#events = res
end
end
you can achieve use a private method to set evnets
class HomeController < ApplicationController
def event_one
set_events
end
def event_two
set_events
end
private
def set_events
Req = **endpoint.connection**
res = req.body**(json format)**
#events = res
end
end
You can also call this method using filter of you want to set for every action of this controller.
Hope this will help!
I have a controller action that is doing product listing, pagination and some filters, like category(from a dropdown), title(from a text-field), stock(from a checkbox)
This is my controller:
class ProductsController < ApplicationController
def index
#products = Product.where(active:1).where("title LIKE ?","%#{params[:title]}%")
if params[:stock]
#products=#products.where("stock = 0")
end
if params[:category]
#products=#products.where("category_id LIKE ?","#{params[:category]}")
end
#products= #products.paginate(:page => params[:page])
#categories= Category.all
end
And my model is:
class Product < ActiveRecord::Base
belongs_to :category
...some validations...
end
What could I change in order that my controller would become thinner? Thanks
Model
class Product < ActiveRecord:::Base
scope :active, where(active: 1)
def self.with_stock(stock=nil)
return where(stock: 0) if stock
self
end
def self.categorized(category=nil)
return self.where(category: category) if category
self
end
def self.titled(title=nil)
return self.where("title LIKE ?", 'title') if title
self
end
def self.list(params)
title = params[:title]
category = params[:category]
page = params[:page]
self.titled(title).with_stock(stock).categorized(category)
.paginate(page).active
end
end
Controller
def index
#products = Product.list(params)
end
Do not ship Category in controller. Do it in template/partial. ONE instance variable from controller only.
I propose the specific refactoring style:
controller
class ProductsController < ApplicationController
def index
#products = Product.titled params[:title]
#products = #products.in_stock if params[:stock]
#products = #products.category params[:category] if params[:category]
#products = #products.paginate :page => params[:page]
#categories = Category.all
end
end
model
class Product < ActiveRecord::Base
belongs_to :category
...
scope :titled, proc {| title | where(active:1).where("title LIKE ?","%#{title}%")
scope :in_stock, proc { where("stock = 0") }
scope :category, proc {| category | where("category_id LIKE ?","#{category}") }
end
If your intent is just to the controller become thinner, you could move the logic to the model.
ProductController.rb
#products = Product.some_method(params)
Product.rb
def self.some_method(params)
if params[:stock]
where("stock = 0 AND active = 1 AND title LIKE ?","%#{params[:title]}%")
end
if params[:category]
where("active = 1 AND category_id LIKE ? AND title LIKE ?", "#{params[:category]}", "%#{params[:title]}%")
end
Using thin controller, fat model principle.
controller:
class ProductsController < ApplicationController
def index
#products = Product.active(params).paginate(page: params[:page])
#categories = Category.all
end
end
model:
class Product < ActiveRecord::Base
belongs_to :category
def self.active(params)
products = where(active:1).where("title LIKE ?","%#{params[:title]}%")
if params[:stock]
products = products.where("stock = 0")
end
if params[:category]
products = products.where("category_id LIKE ?","#{params[:category]}")
end
end
end
I have a filter shared between some controllers, which is primarily declared as private in ApplicationController. This method sets find and pagination conditions for controllers.
class ApplicationController < ActionController::Base
...
protected # or private
# Define parametros de busca
def set_find_opts(klass)
#filter = params[:f].to_i || nil
#order = klass.set_order params[:o]
#opts = { :page => params[:page] }
#opts[:order] = #order if #order
end
...
end
class Admin::UsersController < AdminController
...
before_filter(:only => :index) {|c| c.set_find_opts User }
...
end
I'm getting this error:
1) Error:
test_should_get_index(Admin::UsersControllerTest):
NoMethodError: protected method `set_find_opts' called for #<Admin::UsersControl
ler:0x848f3ac>
app/controllers/admin/users_controller.rb:4
functional/admin/users_controller_test.rb:9:in `test_should_get_index'
Why it happens?
You can't send private/protected messages with an explicit receiver (object.protected_method) like you are doing in your block. You can try c.send(:set_find_opts, User) or c.instance_eval { set_find_opts(User) }.