Method with equals sign not working in Rails - ruby-on-rails

I have a controller with some dummy methods to test why this isn't working (seen in Rails 4):
class Foo::BarController < ApplicationController
before_action :foo
protected
def foo
session[:foo] ||= rand(100)
bar
end
def foo=(n)
puts "Reassigning foo"
session[:foo] = n
end
def bar
foo=(33)
puts "Session is #{session[:foo]}"
end
When I visit any routes in a controller that inherits from Foo::BarController, the logs show e.g. Session is 12, and the foo= method is never evaluated.
How do I get this setter method to fire?

Call foo= as self.foo= as shown below.
def bar
self.foo=(33)
puts "Session is #{session[:foo]}"
end
Without self, foo was treated as local variable and the method foo= was never invoked.

Related

Rails early return if before_action attribute set fails

I would like to perform a db lookup using the incoming request's remote_ip before any controller method is hit in order to set a particular controller class attribute. However if the lookup fails (if no object is linked to the request IP) I would like to immediately return a 404 response.
For example:
class Controller < ApplicationController
before_action :set_instance_or_404
def index
# do something with #instance
end
private
def set_instance_or_404
#instance = Model.find_by(ip_address: request.remote_ip)
# or if no instance is found, immediately return a 404 without hitting "index" method (or any other method for that matter)
end
end
Any help will be greatly appreciated!
You can raise an ActiveRecord::RecordNotFound exception, which will stop the action and return a 404. Or you can render or redirect which will also stop the action. See Rails Filters docs. Here are examples of each.
class Controller < ApplicationController
before_action :set_instance_or_404
def index
# do something with #instance
end
private
def set_instance_or_404
#instance = Model.find_by(ip_address: request.remote_ip)
raise ActiveRecord::RecordNotFound unless #instance # returns 404
end
end
class Controller < ApplicationController
before_action :set_instance_or_404
def index
# do something with #instance
end
private
def set_instance_or_404
#instance = Model.find_by(ip_address: request.remote_ip)
render(status: 404, inline: "Instance not found") unless #instance
end
end

Not able to access controller instance variable in rails helper?

I am trying to access helper method in my controller using helpers like below:
class MyController < ApplicationController
def index
#foo = 'bar'
helpers.my_helper_method
end
end
Inside Helper method, I am trying to access an instance variable of controller
module MyHelper
def my_helper_method
#some manipulation on foo
#foo.to_i
end
end
But in above scenario #foo is nil. When I call the same method from view, #foo is available. So the instance variable can be passed to helper method only through UI or some other way is there?
Thanks in advance.
UPDATE:
view_context
seems like reasonable solution https://apidock.com/rails/AbstractController/Rendering/view_context
class MyController < ApplicationController
def index
#foo = 'bar'
helpers.my_helper_method(#foo)
end
end
module MyHelper
def my_helper_method(foo)
#some manipulation on foo
foo.to_i
end
end
pass it as argument.
You can access instance variables that you set in a controller in your helpers. If the value is nil, then you need to deal with it in your helper:
module SomeHelper
def do_something
return 0 if !#value
value * 3
end
end
class SomeController
def index
#value = 1
helpers.do_something
end
def show
#value = nil
helpers.do_something
end
end

Access helper setter in controller

Let us say I have a helper like this:
module ApplicationHelper
def foo
#foo
end
def set_foo(foo)
#foo = foo
end
def foo=(foo)
#foo = foo
end
end
and a controller like this:
class ApplicationController < ActionController::Base
include ApplicationHelper
def index
foo = 'hello'
end
end
I wonder to know why in the controller neither foo = 'hello', nor foo=('hello') invokes the helper's method foo= but set_foo 'hello' does invoke its method set_foo?
The short answer is, it will just set a local variable in the controller method called foo.
If you call self.foo = 'hello' Ruby will know that foo is a method that should be called.
Worth noting is that this is a completely wrong usage of Rails view helpers.

Rails How to test a method receives block argument with Rspec

Lets say I have this in application controller:
class ApplicationController < ActionController::Base
def example(&block)
...code here
end
end
and this in another controller:
class OtherController < ApplicationController
def index
example { some_text("irrelevant_text") }
end
private
def some_text var
"#{var}_string"
end
end
I want to test that when calling the index action example method gets called with the irrelevant_text_string argument.
Something like:
describe 'index' do
it 'should call example' do
controller.should_receive(:example).with("irrelevant_text_string")
get :index
end
end
But this isn't working. I keep getting
received :example with unexpected arguments
expected: ("irrelevant_text_string")
got: (no args)
Why does it say no args?
Any help will be appreciated
Because you are passing a block to it, not an argument.

Ruby classes inheritance or whatever problem

my ruby (on rails) class looks like:
class Foo
def self.method1
someAction
end
def self.method2
someAction
end
def someAction
//doSmth
end
end
any ideas how to make this work or achieve the same behavior some other way?
thanks!
If some_action is appropriate as a class method, I'd do it like this:
class Foo
def self.method1
some_action
end
def self.some_action
# do stuff
end
def some_action
self.class.some_action
end
end
If method1 is supposed to be a convenience method, then I'd do like Hates_ said to.
class Foo
def self.method1
self.new.some_action
end
def some_action
# do stuff
end
end
The decision for me is usually whether some_action is more of a utility method (like generating a random key, in which case I'd pick the first form), or if it's an entry point to something more complex (like a parser, in which case I'd pick the second form).
You cannot call an instance method from a class method, without an actual instance of the class itself. You can do it as such:
class Foo
def self.method1
myFoo = Foo.new
myFoo.someAction
end
def someAction
//doSmth
end
end

Resources