I have defined a problems method in my Report model. I need to use the value of Report.problem in the report's controller while defining the action show. But i keep getting the error message 'undefined method problem'. How do i solve this? Any assistance would be greatful.
I have a report model and a problem model that contains a list of all problems.
In report model
def problems1
Problem.find(:all, :conditions => )
end
In the reports controller i need something like
def show
#report = Report.problems1
end
you have to assign self.method_name to use as a class method
Follow following rule for Model methods
Class Method
def self.problem
end
in controller
Report.problem
Instance method
def problem
end
in controller
report = Report.new
report.problem
If you define method as class method
class Report < ActiveRecord :: Base
def Report.problem
puts 1
end
end
Report.problem
>1
But if you define method as object
class Report < ActiveRecord :: Base
def problem
puts 1
end
end
This method call
report = Report.new
report.problem
>1
Related
Question is in my rails app I have method called range days I only want this to work if the controller action is create_half how can I do this? any help would be greatly appreciated!!
This is my entry model
class Entry < ActiveRecord::Base
self.primary_key = 'id'
//This is what I want to only happen when my controller action is create_half
def range_days
self.range_days = only_weekdays(leave_start.to_date..(leave_end.to_date)).to_d
end
This is my entry controller
class EntryController < ApplicationController
def half_day
#entry = Entry.new
render :half_day
end
Change your attribute name from range_days to something else. Otherwise you won't be able to get the value in range_days action.
self.range_days in range_days method will call the range_days method again instead of the range_days attribute. As a result it will become an infinite loop and you will get a Stack Level Too Deep exception.
Then you can simply do the following in your controller:
def create_half
#entry = Entry.new
#entry.range_days
...
end
I assume you are looking for a railsy way to do this. Its not needed:
class EntryController < ApplicationController
def create_half
#entry = Entry.new.range_days
#other stuff
end
end
Should do you fine.
In my Rails app there is a view with a simple user form consisting of a text box and a submit button.
When the user submits the form, depending on his input, different models are created:
class MessageController < ApplicationController
def create
if is_foo params[:text]
Foo.create
else
Bar.create
end
end
def is_foo(text)
# Here the message gets parsed
# i.e if text[0] == "M"
end
end
My question is, do you think that it's a better design to put the "is_foo" logic inside the Foo model instead of the controller like so?
Model:
class Foo < ActiveRecord::Base
def self.is_foo(text)
# Here the message gets parsed
# i.e if text[0] == "M"
end
end
Controller:
class MessageController < ApplicationController
def create
if Foo.is_foo params[:text]
Foo.create
else
Bar.create
end
end
end
On one hand, the model should take care of the logic. On the other, this isn't really logic, its more of an input rule... What do you think guys?
Helper
I'd leave the is_foo out of the model, as model logic should be to do with the model directly, not determining which model should be created / saved
I would personally look at using a helper method for the test - calling the file ControllerHelper or similar:
#app/helpers/controller_helper.rb
class ControllerHelper
def is_foo? text
# Here the message gets parsed
# i.e if text[0] == "M"
end
end
This will allow you to call the helper in your controller, giving you the ability to use the logic to form the fixes:
#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
include ControllerHelper
def create
model = is_foo?(params[:text]) ? "foo" : "bar"
model.constantize.send(:create)
end
end
I wouldn't call it a ControllerHelper module as mentioned in Rich Pecks answer (since helpers in Rails are view-related), but something like
# app/lib/foo_bar_creator.rb
FooBarCreator = Struct.new(:params) do
def create
build.save
end
def build
klass.new
end
def is_foo?
params[:text] == 'foo'
end
def klass
is_foo? ? Foo : Bar
end
end
(some call these kind of classes "Service Objects")
This way I could just call FooBarCreator.new(params).create in my controller.
I know this sounds like a ridiculous question but I trying to solve a chalange given by an potential employer. I have a schema and a couple of models with their methods. Almost all the methods have no variables passed in. Meaning none of the methods look like this:
def this_is_my_method(variable)
#stuff
end
or
def this_is_my_method variable
#stuff
end
but there are methods that are clearly working with variables like this:
def build_address
if variable
# do something
end
end
Is there a RoR way that a model method will just know about certain parameters or variables in certain situations?
So if my controller was recieving params that looked like this:
?my_method[begin]=1&my_method[end]=5
would the model method "my_method" know what "begin" and "end" where?
def my_method
if self.begin == self.end
# do something
else
# do something else
end
end
Remember that a model method has access to all the attributes (and other methods) of that model instance.
So (for example) this would be a valid model method.
class User < ActiveRecord::Base
def full_name
[first_name, last_name].join(' ')
end
end
This is taking an attribute user.first_name and an attribute user.last_name and combining them to create a new method user.full_name
EDIT as #Sanket has suggested you can pass values into a model if you make them attribute accessor...
def SomeController < ApplicationController
def some_controller_method
#user = User.find(params[:id])
#user.begin = params[:begin]
#user.end = params[:end]
#user.some_model_method
end
end
def User < ActiveRecord::Base
attr_accessor :begin, :end
def some_model_method
if self.begin == self.end
# do something
else
# do something else
end
end
end
Although to be frank I'd rather just pass the values in as method arguments.
class HouseBuyersController < ...
def my_method
# How could I get here the relevant model name, i.e. "HouseBuyer" ?
end
end
This will do it:
class HouseBuyersController < ApplicationController
def index
#model_name = controller_name.classify
end
end
This is often needed when abstracting controller actions:
class HouseBuyersController < ApplicationController
def index
# Equivalent of #house_buyers = HouseBuyer.find(:all)
objects = controller_name.classify.constantize.find(:all)
instance_variable_set("##{controller_name}", objects)
end
end
If your controller and model are in the same namespace, then what you want is
controller_path.classify
controller_path gives you the namespace; controller_name doesn't.
For example, if your controller is
Admin::RolesController
then:
controller_path.classify # "Admin::Role" # CORRECT
controller_name.classify # "Role" # INCORRECT
It's a bit of a hack, but if your model is named after your controller name then:
class HouseBuyersController < ApplicationController
def my_method
#model_name = self.class.name.sub("Controller", "").singularize
end
end
... would give you "HouseBuyer" in your #model_name instance variable.
Again, this makes a huge assumption that "HouseBuyersController" only deals with "HouseBuyer" models.
For namespaces working:
def resource_class
controller_path.classify.constantize
end
The accepted solution did not work for me as my controller and model was namespaced. Instead, I came up with the following method:
def controllers_model
(self.class.name.split('::')[0..-2] << controller_name.classify).join('::')
end
This is not possible if you are using the default MVC, which your code doesn't seem to follow. Your controller seems to be a model but maybe you just got a type there. Anyway, controllers and models are fundamentally separated in Rails MVC so controllers cannot know which model they are associated with.
For example you could have a model named post. This can have a controller posts_controller or could have a controller like articles_controller. Rails only knows about models when you def the actual code in the controller such as
def index
#posts = Post.all
#posts = Article.all
end
In rails standard controllers there is no way to know what the model is.
I am trying to do a custom active record macro. But it right now seems impossible set an instance variable from within it's block.. here is what i am trying to do.
module ActiveRecord
class Base
def self.included(base)
base.class.send(:define_method, :my_macro) do |args|
# instance_variable_set for the model instance that has called this
# macro using args
end
end
end
end
i have tried class_eval, instance_eval.. but nothing seems to work or i don't how to use them.
Thanks in advance.
Edit: Let me try to explain better. I have a class method. An instance of the class calls this method. Now, this class method should instruct the instance to set an instance variable for itself.
Edit- this is how i want o use the macro
class MyModel < ActiveRecord::Base
my_macro(*args)
def after_initialize
# use the value set in the macro as #instance variable
end
end
Is this what you are thinking of:
class DynamicAdd
def add_method
self.class_eval do
attr_accessor :some_method
end
end
end
You can then do the following:
k = DynamicAdd.new
k.some_method = "hi"
should result in an undefined method error.
But,
k = DynamicAdd.new
k.add_method
k.some_method = "hi"
should work.
You can use this same format to define other types of methods besides attr_accessors as well:
class DynamicAdd
def add_method
self.class_eval do
def some_method
return "hi"
end
end
end
end
Hm.. Isn't included() a Module method? I don't think you can use that in a class like you have written. If you want to create a class method you can do
class Base
def self.my_method
end
or
class Base
class << self
def my_method
end
end
If all you want to do is to add an instance variable to an existing object, then you can use #instance_variable_set
class Base
class << self
def my_method(instance_of_base, value)
instance_of_base.instance_variable_set "#x", value
end
end
end
a = Base.new
a.class.send(:my_method, *[a,4])