NoMethodError - undefined method error - ActiveRecord - ruby-on-rails

I'd like to return a random webpage that I can display as a link in a view but I can't get the method to work properly:
Error:
NoMethodError: undefined method `randomize_webpages' for #<ActiveRecord::Relation::ActiveRecord_Relation_Webpage:0x00000101d84e68>
Webpage Model
def randomize_webpages
shuffle.first
end
WebpagesController
def index
#webpages = Webpage.all
end
CSV seeder for Webpage
link
http://www.buzzfeed.com
http://www.reddit.com
http://boston.com
http://phys.org
http://www.popsci.com
http://www.technologyreview.com
http://techcrunch.com
View Index.html.erb
<%= link_to 'Take Me Anywhere But Here', #random_page %>

You need to define the method as a class method of the model
class Webpage
def self.randomize_webpages
shuffle.first
end
end
instead of
class Webpage
def randomize_webpages
shuffle.first
end
end
Please note that the method is very inefficient. You are loading all the records and then selecting one. There are more efficient ways.
One possible improvement is to select only the ID, then query for that ID. Another alternative is to delegate to the underlying driver, assuming it supports the query.

Aren't you calling randomize_webpages on #webpages, are you? This is a collection, so you have to do something like #webpages.first.randomize_webpages or iterate over them (you didn't include relevant code so I can't tell what you want to do) to get this working.

It needs to be a class method, then you could use sample:
def self.randomize_webpages
all.sample
end

You could add a class method to your model
class WebPage < ActiveRecord::Base
def self.random
order('RAND()').first
end
....
end
Then you can call it from as WebPage.random in your controller, save to an instance variable, and use that instance variable in your view.
Please: note that 'RAND()' is MySQL specific. If you do not use MySql, search for the correct syntax (if any)

Related

how can I change class method to instance method in ruby?

Now, I am facing the problem of creating an instance method.
Item has multiple images in active storage.
I created a class method something like below.
def self.get_url(item)
item.images.map do |image|
Rails.application.routes.url_helpers.url_for(image)
end
end
this class method worked completely fine.
But I want to change this to instance method so that I use this other place without an argument item.
So I want it to be something like this.
def get_url
item.images.map do |image|
Rails.application.routes.url_helpers.url_for(image)
end
end
But I can't do this, because nothing like item is defined.
And I want to use it like this.
item.get_url
If you could help me I would really appreciate it.
Thank you.
In def self.get_url(item), I'll assume item is an instance of the class, so if you want to create an instance method, simply drop the item part from item.images:
def get_url
images.map do |image|
Rails.application.routes.url_helpers.url_for(image)
end
end

Access a instance method from other model in ruby on rails?

I have a user model in my application. Now I want to replace some user model coding into 2 categories likely employ.rb and customer.rb under a module users, to avoid more number of codes in a single model. I want to access a method send_mail in customer.rb after a user created.
user.rb
after_create:send_msg_on_order
def send_msg_on_order
Users::Customer.send_mail
end
users/customer.rb
def send_mail
Mailer.send_mail_to_customer.deliver
end
And I am getting undefined method `send_mail' for Users::Customer:Module error.
You have defined send_mail method as instance method but calling it as a class method. Either make it a class method or create an instance of Customer model and call it.
Making the method a class method:
def self.send_mail
Mailer.send_mail_to_customer.deliver
end
If you wish to keep it an instance method, then call it like this:
after_create:send_msg_on_order
def send_msg_on_order
Users::Customer.new.send_mail
end
HTH
You can also call like this
def send_msg_on_order
Customer.send_mail
end

NameError: undefined local variable or method `desired_preferences'

I have created a module with a method
module Adding_preferences
def desired_preferences
#preference = %w(motabilitySpecialist newCars bodyshop filter8 filter7).each do |selection|
#browser.label(:for, selection ).click
end
end
end
I have included this module into a class:
class Pages
include Adding_preferences
attr_accessor :browser, :preference
def initialize
#browser = Watir::Browser.new :ff
end
end
World do
Pages.new
end
I am calling this method in a Cucumber scenario
When /^I select a desired preference$/ do
desired_preferences
end
But at runtime I receive an error, "NameError: undefined local variable or method `desired_preferences'". Where am i going wrong?
When you include a module to a class you can use this method in the instance methods of this class. You cant call the included method in a View that displays the data from the model that includes the module. For me it looks like you just dont use the desired_preferences method in an instance method.
Please show us the peace of code you try to call the method if this still doesnt help you out.
// The naming of the Module is not conventional. You should call it module AddingPreferences isntead ofmodule Adding_preferences and the file should be named adding_preferences.rb then try to include AddingPreferences
It's a good idea for you to spend some time getting more familiar with Ruby's Class/Module/Object/Method inheritance model, because the way you're structuring your code there is a little bit messy.
However, a simple thing to try (and I'm not going to guarantee that it will work flawlessly) is the following modifications:
Assign your instantiated Pages class to a class instance variable:
World do
#page = Pages.new
end
...and then use that instance variable in your step definition...
When /^I select a desired preference$/ do
#page.desired_preferences
end
I hope that helps!

Call a model method in a Controller

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)

Can I define_method in rails models?

My rails model has code that is attempting to define_method(method_name) inside the model.
I keep getting:
NoMethodError: undefined method `define_method'
What am I doing wrong? Am I doing this in the wrong place. I need this method attached to this model. Where else can I define this method?
EDIT:
For those asking to see the code:
for field in rdev_fields
next if self.attributes.include?(field)
count = count + 1
rdev_hash[field.to_sym] = self.attributes["attribute#{count}"]
if !self.respond_to?(field) then
define_method("#{field}") do
self.send("attribute#{count}".to_sym)
end
end
end
There's nothing magical or about a rails model, it's just a normal class with a bunch of pre-existing methods,
So, the question is "can I define_method in a class"?
Part 1: Yes you can.
The important distinction is than you can define method in a class not in an instance method
For example:
class Cow
define_method "speak" do
"MOOOO"
end
end
Cow.new.speak
=> "MOOOO"
This should work fine. Note you're defining it on the class Cow, so any other Cows that you already have will automatically get that method added.
Part 2: What do you do if you want to define a method from within an instance method?
You can't define methods from an instance method, so you have to grab the class, and use that to define the method. Like this:
class Cow
def add_speak
self.class.send(:define_method, :speak) do
"MOOOO added"
end
end
end
Cow.new.speak
NoMethodError: undefined method 'speak' for #<Cow:0xb7c48530>
Cow.new.add_speak
Cow.new.speak
=> "MOOOO added"
Problem solved. Astute readers will note that in this example I'm using send(:define_method) - this is needed because define_method is private, and private methods are only accessible to the thing they're in. In this case, define_method is in the class, we are in the instance, so we can't directly access it.
As above though, we're adding the method directly to the class, so all other Cows which already exist will automatically also get the speak method added.
Part 3: What do you do if you want to define a method for only 1 object, not all objects of that class?
Example:
class Cow
def add_speak_just_me
class << self
define_method "speak" do
"MOOOO added for just me"
end
end
end
end
Cow.new.speak
NoMethodError: undefined method 'speak' for #<Cow:0xb7c72b78>
c = Cow.new
c.add_speak_just_me
c.speak
=> "MOOOO added for just me" # it works, hooray
Cow.new.speak # this new cow doesn't have the method, it hasn't been automatically added
NoMethodError: undefined method `speak' for #<Cow:0xb7c65b1c>
How does this work? Down the rabbithole you go!
Read this: http://dannytatom.me/metaid/ and good luck. It helps when you realise that 'adding a method' to an instance isn't actually adding it to the instance at all :-)
If you came here searching for how to dynamically define a CLASS method, because define_method wasn't working (because it defines INSTANCE methods), here is your answer:
Use define_singleton_method :)
was able to cobble this together. Very little understanding of what's actually going on though.
My instance method foo is opening the class and defining bar on it so that I can then call that on my instance. More experienced folks will let us know if this is opening a can of worms at the same time.
Would be useful to know your specific use for this though.
class User < ActiveRecord::Base
def foo
(class << self; self; end).class_eval do
define_method(:bar) {puts "bar"}
end
end
end
u = User.first
u.foo
u.bar #=> "bar"
The answer to your question is "yes, you can". As for why it's not working for you - it's impossible to say for sure why, if you don't provide some context for the code.

Resources