I'm using rails ActiveModel, I defined 2 methods like this:
def find_existing_task(task)
existing_one = Task.find(task.id)
end
def find_existing_person(person)
existing_one = People.find(person.id)
end
But I think I need a more generic method like this:
def find_existing(any_active_model_instance_with_id)
existing_one = ActiveModelClass.find(any_active_model_instance_with_id.id)
end
But I don't know how to call the class method given an instance, in above, given task, I can call Task.find without specifing class name "Task"
Any solution? thanks!
You can do it with the following code
def find_existing(some_model)
existing_one = some_model.class.find(some_model.id)
end
Related
I have a handler which is responsible for creating a new record in db.It takes params from the POST requests and adds a new record to database.That helper is defined below:
module Vehicles
module Handlers
class AddVehicle
def initialize(vehicle_params)
#vehicle_info = vehicle_params
end
def call
create_vehicle
end
private
def create_vehicle
Vehicle.create!(#vehicle_info)
end
end
end
end
I would like to test If that class methods work properly but without issuing the POST request.So I don't need to create data with factory_bot but simply puts arguments when calling the method. Do you have an idea how to test this behaviour?
A handler is a class, so just need to do something like this...
h = Vehicle::Handlers::AddVehicle.new(vehicle_params)
to get an instance of the handler. Then you can test as you would any other class. For instance...
vehicle = h.call
refute_nil vehicle
I am rather new to Rails, and would greatly appreciate any bit of help. I have created the following method:
def name_fix
name = self.split
mod_name = []
name.each do |n|
n.split("")
if n[0]
n.upcase
else
n.downcase
end
mod_name.push(n)
end
mod_name.join
end
I would like to use this method in my Controller as such:
def create
#patient = Patient.new(params[:patient])
#patient.name = params[:params][:name].name_fix
if #patient.save
redirect_to patients_path
else
render :new
end
end
How can I go about accomplishing this? Will this method reside within my Model or Controller? Previously, I've run into an undefined method error.
Note: I'm sure that there is a way to better write my code. I am grateful for help with that as well.
#app/models/patient.rb
class Patient < ActiveRecord::Base
protected
def name=(value)
mod_name = []
value.split.each do |n|
n.split("")
type = n[0] ? "up" : "down"
n.send("#{type}case")
mod_name.push(n)
end
#name = mod_name.join
end
end
#app/controllers/patients_controller.rb
class PatientsController < ApplicationController
def create
#patient = Patient.new patient_params
#patient.save ? redirect_to(patients_path) : render(:new)
end
private
def patient_params
params.require(:patient).permit(:name)
end
end
What you're doing is trying to override the setter method, which can be done using the above code. Much more efficient and out of the way.
I have created the following method
Since you're new, let me explain something else.
It is important to note where you're using this method.
You've currently put it in the model, which means you'll have to call it to manipulate some attribute / functionality of any object created with said model.
--
Models - in Rails - build the objects which populate your app. Ruby is an object orientated language, which means that every element of your program should revolve around data objects in some degree.
As you can see above, the method of building objects in your system is really about invoking classes. These classes contain methods which can be called, either at class level (IE invoking the class through the method), or at instance level (IE calling a method on an already invoked object).
This is where you get "class" methods (Model.method) and "instance" methods (#model.method) from:
#app/models/patient.rb
class Patient < ActiveRecord::Base
def explode
#this is an instance method
puts "Instance Explode"
end
def self.explode
#this is a class method
puts "Exploded"
end
end
Thus you can call the following:
#patient = Patient.find params[:id]
#patient.explode #-> "Instance explode"
Patient.explode #-> "Exploded"
--
This is important because it gives you a strict framework of where you should, and shouldn't use methods in your models.
It explains why you have controllers & helpers, and allows you to formulate the best way to structure your application as to get the most out of the least code.
For example...
Your use of #patient.name = params[:params][:name].name_fix is incorrect.
It's wrong because you're calling the instance method .name_fix on a piece of data totally unrelated to your model. If you wanted to use .name_fix in a general sense like this, you'd probably use a helper:
#app/helpers/patients_helper.rb
class PatientsHelper
def name_fix value
# stuff here
end
end
#app/controllers/patients_controller.rb
class PatientsController < ApplicationController
def create
#patient.name = name_fix params[:patient][:name]
end
end
Since you're using the method to populate the .name attribute of your model, it makes sense to override the name= setter. This will not only provide added functionality, but is much smoother and efficient than any other way.
Methods that are called directly are best put in the Controller (or in ApplicationController if you think more than one controller might want to use it).
These are methods like
# app/controllers/my_controller.rb
def foo(bar)
# do something here
end
def create
id = params[:id]
value = foo(id)
end
If you want a chained method that acts as a property method of whatever you're calling it on. Those are characteristic of how Models work - you have your main model and you call attributes or methods on the instance of that model.
# app/models/my_model.rb
def full_name
first_name + " " + last_name
end
# app/controller/my_controller.rb
def create
id = params[:id]
model = MyModel.find(id)
full_name = model.full_name
end
In your case, you want to call name_fix ON whatever is returned by params[:params][:name], which is (I'm guessing) a String.
You have two options
Modify the String class to define a method named name_fix. I highly recommend against this. It's call "monkeypatching" and shouldn't be done without good reason. Just letting you know you can do it in some cases.
Use a direct method in your controller or ApplicationController like the first example above.
#patient.name = name_fix(params[:params][:name])
Edit: As for your request about a better way to write your code... that's difficult to teach or convey in one answer. I'd say read some open source projects out there to see how people write Ruby and some common idioms used to clean up the code. To get you started, here's how I'd re-write your code
def create
#patient = Patient.new(params[:patient])
# 1. Be descriptive with your method names. `name_fix` is vague
# 2. Why is `:name` nested under another `[:params]` hash?
#patient.name = capitalize_name(params[:name])
if #patient.save
# 1. I think `patient_path` has to be singular
# 2. It needs a `Patient` object to know how to construct the URL
# e.g. `/patients/:id`
redirect_to patient_path(#patient)
else
render :new
end
end
def capitalize_name(full_name)
# Example: julio jones
#
# 1. `split` produces an array => ["julio", "jones"]
# 2. `map` applies a function (`capitalize`) to each element
# => ["Julio", "Jones"]
# 3. `join(" ")` rejoins it => "Julio Jones"
full_name.split.map(&:capitalize).join(" ")
end
Assuming your goal with the name_fix method is just to capitalize the first letter of each name, you could just pass name as an argument and store it as a private method on the Controller:
# app/controllers/patient_controller.rb
private
def name_fix(name)
name.split.map(&:capitalize).join(" ")
end
Then you could do
#patient.name = name_fix(params[:params][:name])
in the create method.
OR, you could store this method in the model:
# app/models/patient.rb
def self.name_fix(name)
name.split.map(&:capitalize).join(" ")
end
Then you could do this instead, in the controller:
#patient.name = Patient.name_fix(params[:params][:name])
I would also suggest renaming your name_fix method to something like capitalize_name.
update your create method as below
def create
#patient = Patient.new(params[:patient])
#patient.name = params[:params][:name]
#patient = #patient.name_fix
if #patient.save
redirect_to patients_path
else
render :new
end
end
It should work.
hi i am new ruby on rails i need to know some basic information about
how to call a function from controller to model
for ex:-
controller name : checkings
def create
#data = Checking.check()
end
model name is Checking
def check
#a="xxxxx"
end
how can i call from controller function to model function
check is instance method,you have to make class method to call by class name,def self.check end
Seems you are referring to static function call. In ruby the static functions are defined with self.
def self.check
a="xxxxx"
end
However, in rails, you should not populate instance variable in Model. In that case you can return the value from check function and assign it in controller function like
def self.check
return "xxxxx"
end
#In controller
#data = Checking.check() # "xxxxx" will be stored in #data
However, defining any function without self means its a instance function. So you need to call that function through any object of that class.
We can call the model methods from controller using two formates,
1 . Creating singleton methods.
Singleton methods are created using self keyword. example
class Check < ActiveRecord::Base
def self.check
end
end
we can call this singleton method using following format,
#checks = Check.check
2 . Creating instance methods.
Instance methods are created using without self keyword
class Check < ActiveRecord::Base
def check
end
end
we can call this singleton method using following format,
#check =Check.new
#checks = #check.check
I'm have some difficulties here, I am unable to successfully call a method which belongs to a ProjectPage model in the ProjectPage controller.
I have in my ProjectPage controller:
def index
#searches = Project.published.financed
#project_pages = form_search(params)
end
And in my ProjectPage model:
def form_search(searches)
searches = searches.where('amount > ?', params[:price_min]) if check_params(params[:price_min])
#project_pages = ProjectPage.where(:project_id => searches.pluck(:'projects.id'))
end
However, I am unable to successfully call the form_search method.
To complete davidb's answer, two things you're doing wrong are:
1) you're calling a model's function from a controller, when the model function is only defined in the model itself. So you do need to call
Project.form_search
and define the function with
def self.form_search
2) you're calling params from the model. In the MVC architecture, the model doesn't know anything about the request, so params is not defined there. Instead, you'll need to pass the variable to your function like you're already doing...
Three thing:
1.) When you want to create a class wide method thats not limited to an object of the class you need to define it like
def self.method_name
..
end
and not
def method_name
...
end
2.) This can be done using a scope with lambda these are really nice features. Like This in the model add:
scope :form_search, lambda{|q| where("amount > ?", q) }
Will enable you to call
Project.form_search(params[:price_min])
The secound step would be to add a scope to the ProjectPage model so everything is at the place it belongs to!
3.) When you call a Class method in the Controller you need to specifiy the Model like this:
Class.class_method
Declare like this in model
def self.form_search(searches)
searches = searches.where('amount > ?', params[:price_min]) if check_params(params[:price_min])
#project_pages = ProjectPage.where(:project_id => searches.pluck(:'projects.id'))
end
and call from controller
#project_pages = ProjectPage.form_search(params)
I have a Rails 2.3.11 controller that I'm trying to debug. It looks like this:
class AppleController < ...
# ...
def create
# ...
end
end
From the log, I have some parameters p:
p = { ... }
What can I write at the console so that I can get an instance of AppleController that will work exactly like a regular instance with those parameters, and which will let me call .create?
ac = AppleController.new
# What goes here?
ac.create
(Notice that just assigning ac.params = p is not sufficient since there's no #request object, etc.) Thanks!
I think this is best done using the ActionController::Integration::Session class
e.g. to call the create method of your AppleController
require 'action_controller/integration'
app = ActionController::Integration::Session.new;
app.post('/apples', params) # assuming '/apples' is the path to your AppleController
puts app.response.inspect
If I am reading the question correctly, you can just call Apple.create(:something => "bah") in the console. That should mimic what the controller does when it gets a post request.