Refactoring controller - ruby-on-rails-3

As I'm sure you can tell by the following code, I'm a newbie. But I have managed to get this to work correctly...
However, I'd really like to know how to refactor this code, as I'm sure its not the best way to do it. Can anyone point me in the right direction?
Thank you very much in advance...
current_controller = params[:controller]
if current_controller == "menus" && params[:id].present?
#menu = Menu.find(params[:id])
elsif current_controller == "menus" && params[:id].nil?
#menu = Menu.first
elsif current_controller == "items" || current_controller == "categories"
#menu = Menu.find(params[:menu_id])
else
#menu = Menu.last
end

A naive translation into (slightly) smaller code:
current_controller = params[:controller]
#menu = if current_controller == "menus"
params[:id].present? Menu.find(params[:id]) : Menu.first
elsif current_controller == "items" || current_controller == "categories"
Menu.find(params[:menu_id])
else
Menu.last
end
Where does this code live?
Would it make more sense to have this in a base app controller, or filter, etc. and override in the three controllers that are special-cased? Or is this wrapped up in a helper, or...?
Edit Using Procs.
# Default if hash entry not found.
menus = Hash.new(Proc.new { |p| Menu.last })
# Items and categories controllers
itemcats = Proc.new { |p| Menu.find(p[:menu_id]) }
menus["items"] = menus["categories"] = itemcats
# Menus controller
menus["menus"] = Proc.new { |p| p[:id] ? Menu.find(p[:id]) : Menu.first }
#menu = menus[params[:controller]].call(params)
(More or less.)

This would be my refactoring to your code:
#menu = case controller.controller_name
when "menus"
if params[:id]
Menu.find(params[:id])
else
Menu.first
end
when "items" || "categories"
Menu.find(params[:menu_id])
else
Menu.last
end

This is untested, but you could try using the case statement as davenewton said
# Case on an expression:
#menus = case params[:controller]
when "menus" && params[:id].present? then Menu.find(params[:id])
when "menus" && params[:id].nil? then Menu.first
when "items", "categories" then Menu.find(params[:menu_id])
else Menu.last
end
You can replace the "then's" with semicolons if you prefer

Related

is there any way that can offset from specific record when using scope

i have a lot of methods that look for records after specific active record. examples are:
def photo_recent
offsetphoto = Photo.find(params[:id])
#photos = Photo.recent.where('created_at> ?', offsetphoto.id).limit(10)#recent is a scope using created_at
end
def photo_recent
offsetphoto = Photo.find(params[:id])
#photos = Photo.popular.where('like_count > ?', offsetphoto.like_count).limit(10)#popular is a scope using like_count
end
i was wondering if there is any way to modularize this such as:
#photos = Photo.recent.offset(Photo.find(params[:id])).limit(10)
# models/photo.rb
scope :most_recent_starting_from, -> (photo) { order(created_at: :asc).where('created_at >= ?', photo.created_at) }
Example Usage
photo = Photo.find(123)
ten_next_created_photos_after_photo = Photo.most_recent_starting_from(photo).limit(10)
You could write a scope that just takes everything from the current Photo
scope :offset_from, -> (photo) { where('id >= ?', photo.id) }
Photo.offset_from(Photo.find(params[:id]))......

regex match mongoid condition

I have item[:name] and I would like to be able to use
(item[:name].scan(/[a-z0-9\s]/i).join rescue "") =~ Regexp.new(business.scan(/[a-z0-9\s]/i).join, true)
as a condition in mongoid. Is there a way to do this? The only solution I have come up with is getting all items, then iterating over that array, doing the regex at that point in time.
The goal of this is to find "John's" when the website is searched for "Johns" and vice versa.
Thanks
Here is what i ended up using.
def self.find_by_name_or_organization(business = nil)
businesses = self.all(:order => "name ASC")
businesses.delete(nil)
if business && !(business.nil? || business.to_s == '')
final_business_array = Array.new
businesses.each do |item|
if (item[:organization].scan(/[a-z0-9\s]/i).join rescue "") =~ Regexp.new(business.scan(/[a-z0-9\s]/i).join, true) ||
(item[:name].scan(/[a-z0-9\s]/i).join rescue "") =~ Regexp.new(business.scan(/[a-z0-9\s]/i).join, true)
final_business_array.push(item)
end
end
final_business_array
else
businesses
end
end

Limit dynamic field with cocoon gem in rails 3

I am using cocoon gem for adding dynamic fields in my webform, now i want to restrict them to add only six fields, how can I do it?
below is the code I am using in my helper:
def link_to_add_association(*args, &block)
if block_given?
f = args[0]
association = args[1]
html_options = args[2] || {}
link_to_add_association(capture(&block), f, association, html_options)
else
name = args[0]
f = args[1]
association = args[2]
html_options = args[3] || {}
html_options[:class] = [html_options[:class], "add_fields"].compact.join(' ')
html_options[:'data-association'] = association.to_s.singularize
html_options[:'data-associations'] = association.to_s.pluralize
new_object = f.object.class.reflect_on_association(association).klass.new
html_options[:'data-template'] = CGI.escapeHTML(render_association(association, f, new_object)).html_safe
link_to(name, '#', html_options )
end
end
Thanks for your help in advance.
You could do that using JavaScript and Cocoon helper method before and after insert. So what you could do
.bind('cocoon:after-insert', function() {
/* ...
1. check to see if the number of nested fields added is equal to what you want
2. if it is equal, hide the link_to_add_association link
... */
})

haml two spaces issue

When using haml I have following problem.
First I want to check one variable and after that render something else, but it still should be nested.
Let me explain
code:
.a
.b
gives: <div class=a><div class=b></div></div>
When I use haml if else, I can't nest .b inside .a:
- if id == 3
.a{style => 'xxx'}
- else
.a{style => 'yyy'}
.b <-- 2 spaces, otherwise it fails. but 2 spaces are causing the following issue:
The problem is, because there is no end in haml, I don't know how to put .b within .a div, in both situations (if id ==3, or else).
As an real live example:
- if home != nil
.home
home.id
- else
.home
empty
- end <--- can't use
- if room != nil <-- without end, this will be executed only if home == nil but I wan't this to be executed always
room.id
- else
empty
because haml doens't support -end, I can't use it. If I don't use it, haml automatically closes div if I start to cehck 'room's values because these are in the same line :)
Example with comparing variable to nil, or doing something only if the variable is nil is just an example. I'm looking for a solution that solves such problem with indenting after else so it applies to the whole statement.
There are similar question: HAML: Indenting if/else statements with common content
So, in your case you would do like:
.a{ :style => id == 3 ? 'xxx' : 'yyy' }
.b
edited:
In case of if... elsif... elsif... you can write your own helper:
.a{ :style => select_style(variable) }
.b
#helper method
def select_style(val)
case val
when "3"
"xxx"
when "4"
"yyy"
else
"zzz"
end
end
Of course you can write it all in haml, but it will be ugly:
- if id == "3" then val="xxx"
- elsif id == "4" then val="yyy"
- else val="zzz"
.a { :style => val }
.b
HAML has its advantages, but it is an example of one of the disadvantages.
edited
Or you can going mad and do like:
.a{:style => if var == "3" then "xxx" elsif var == "4" then "yyy" else "zzz" end}
You could also try this:
- if contition
- attrs = { class: '..', id: '..' }
- else
- attrs = { style: '...' }
.a{attrs}
.b
There are similar question: HAML: Indenting if/else statements with common content
So, in your case you would do like:
.a{ :style => id == 3 ? 'xxx' : 'yyy' }
.b
edited:
In case of if... elsif... elsif... you can write your own helper:
.a{ :style => select_style(variable) }
.b
#helper method
def select_style(val)
case val
when "3"
"xxx"
when "4"
"yyy"
else
"zzz"
end
end
Of course you can write it all in haml, but it will be ugly:
- if id == "3" then val="xxx"
- elsif id == "4" then val="yyy"
- else val="zzz"
.a { :style => val }
.b
HAML has its advantages, but it is an example of one of the disadvantages.
edited
Or you can going mad and do like:
.a{:style => if var == "3" then "xxx" elsif var == "4" then "yyy" else "zzz" end}

Rails 3 : Add some methods in models, for development

I would like to add some methods to some AR Models of my App; but I think they should only be available under some circumstances; this requires some meta-programming.
So I'd like to have a file where I put all my debug methods, the only question is where to put it?
Example, I have the models:
class Admin::Restaurant < ActiveRecord::Base
class Admin::Order < ActiveRecord::Base
And in my file I have (it does deppend on MetaWhere.operator_overload! initialization):
if Rails.env != 'production'
class Admin::Order
def self.mock_make
r = Restaurant.first
user_query = User.where( :created_at > "2011-04-01" )
u = user_query.first( :offset => ( user_query.count * rand ).to_i )
o = r.orders.new
o.user = u
o.value = rand(100) + rand.round(2)
if o.save
return o
else
return nil
end
end
end
end
The thing is.. I can't get it to work on /config/initializers or /app/models.
Wrap it as a external module and include it with if condition
class MyClass << ActiveRecord::Base
include MyExtraModule if Rails.env == 'development'
end
Put them in config/environments/development.rb