I've read the documentation, and it confuses me every time, just because it doesn't answer some basic things. I realize the main purpose of the class method ::respond_to (which is normally used at the top of the controller) is for use in conjunction with respond_with. And the purpose of the instance method #respond_to (normally at the end of each action) is to provide different responses for different formats.
I also know that it's possible to consolidate the instance method version to look like the class method, but used inside an action, for conciseness, like this: respond_to(:html). The use case for this is another purpose of #respond_to, which is to refuse requests for unspecified formats. (I think it raises an UnspecifiedFormat exception)
Does the class method also have the same functionality? For instance, if I have a controller that only responds to html, if I just put respond_to(:html) at the top of the file, can I expect it to refuse requests for other formats? I've had problems with it doing that, so I don't know if I've been doing something wrong, or if it's just not supposed to work the same as the instance method in that respect.
So I finally ran an experiment, and no, the class method respond_to does NOT refuse requests to unspecified formats like the instance method does. Kind of a confusing disparity, but there you have it. If you want to refuse requests for invalid formats (with a 406), you have to specify valid formats inside each action of each controller (using the instance method respond_to)
Related
I'm creating a wrapper class for an API because my application will need to call it with different credentials at different times. I started off passing the wrapper a method and arguments and then doing (basically) this when calling it
call
set_credentials
TheAPI::Thing.send(method, args)
ensure
reset_credentials_to_default
end
HOWEVER, I realized that a challenge here is if I need to chain methods; this way I can only call one at a time; so for example I wouldn't be able to to TheAPI::Thing.find(id).delete. (At least, not without re-calling the credentials setter, which is undesirable since I have to fetch a token).
Is there a way using ruby to collect the methods/args being chained onto an object? Or would I simply have to pass in some ugly ordered set of things?
EDIT: Surely activerecord's query builder does something like this, collecting the chained methods before returning, and then after they're all collected, ensuring that as a final step the query is built, called, and returned?
the way to do this is to define a proxy object and to pass that around instead of the actual thing.
In the object itself, hold a reference to the Thing and override method_missing: http://ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing
In the method missing do the thing you are doing today. In a nutshell this is what ActiveRecord is doing.
As far as chaining things, I don't believe it would be a problem as methods that can be chained usually return references to self. When you call the 2nd method in the chain, you actually have done the work for the first one and have an object that has the 2nd method in the chain. The only trick you need to pay attention to is that you want to return a reference to the proxy class that encapsulates the thing instead of the actual return of the thing if you want the chaining to succeed.
Give it a shot and ping me if you run into trouble and I can spin up a fully working example.
I'm relatively new to rails, but I've made a few basic CRUD apps. However, this time, I'm making something different, and I'm not sure how to organize it.
It's essentially a one page app. The user fills out a form, and the code does some calculations based on those values. I have all the code written, but it's all just sitting in the controller. I'm assuming that this isn't correct.
There are two parts:
Using an external API, 2 constant arrays are generated. I need these variables to be global, or at least accessible for the calculator function.
I have a function that takes some inputs from the form that also calls other functions. A simplified version is below. I could put all the code into one function if that's necessary. I have them separate just so that the code is more readable.
def calc(input)
func1(input)
func2(input)
# do more stuff
return answer #I need to show this in the view
end
def func1(a)
end
def func2(b)
end
So, where should I put each part of this code?
To make your controllers thin, you can keep business logic at Service Objects.
Just create "services" directory at "app", add there some class like "user_searcher.rb".
And call it in the controller, passing all necessary data.
Such technique will help you to isolate business logic and incapsulate it in separate class.
BTW read this article http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
I think, from what I understand of you question, is this code should be placed in the helper classes. If you have dedicated class for this calculation, you can use class attributes to access array to access anywhere in the class or declare them constant, in case they are constant.
I don't think making global is a good practice, just because this is needed in some other function, instead return that variable and pass them as parameter where they are needed.
If the end_user cannot access the source code of the app, why we still need to make some methods private?
I'm reading the Pragmatic Agile Web Development with Rails and I couldn't understand why we need to make the following method private (even after reading the explanation):
private
def current_cart Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
end
It says that it will never allow Rails to make it available as an action, but as a coder, why would I ever do that myself?
As you say there may be no external reason to make it private. However, it also prevents you — or somebody else using your code — from accidentally making use of the method where you're not supposed to.
See it as a sanity check on your own future behaviour if you will.
It aims to encourage good practices and good code.
The idea is that you have two separate parts to your code:
"Above the line" (Public). This is the interface to the rest of the world. This is the API, where calls are made when using instances of the object. Once created, you know that THIS is the area where changes can affect current usages of the code.
"Below the line (Private). This is where detailed logic resides. This code can be changed and refactored freely without any affect to the public interface.
It may help guide your test writing
Private methods may or may not be (unit) tested.
Public methods are more encouraging of both unit and integrated tests as the fact that is is public means that it is serving as the public face for that code and as it is public it might be called from any other point in the future, so having good tests to make sure it continues to work as advertised is essential.
It may help with security as you have greater control who calls private methods (i.e. only public methods in the same class calling them).
It may help reduce name collisions as you have less names in the public space.
End user might not be able to access your code but someone else in your team can definitely access it and they might change it.
The other benefit of encapsulation is that it allows one class ("server") to make a contract with another class ("client") to provide some service with only a very few things being required to be known about the "server" class such as method signature and return type. The benefit is only realized if the contract of what is required and what is returned remains the same. So, in your example, there is no benefit since the contract was broken by Class A.
Instead of class A changing int type to float, class A should create another new variable of type float for other classes to use so that class B is not "broken" or that contract is not broken between them. Class C could refer to new float variable and Class B could still refer to old int variable and everyone is happy. Better yet, methods would used to retrieve values such as: "getUsersAddress" and "getUSersPhoneNumber" depending on what was wanted.
The real benefit of good encapsulation is that Class A can be completely re-written from top to bottom and as long as the contract is honored as to what Class A is expected to do(have methods "getUsersAddress" and "getUSersPhoneNumber"), then everything in Class B and C works the same. Think carefully about what is exposed and how it is exposed. Things that will change often and break other classes need to be considered carefully before exposing. Good encapsulation means hiding things that are expected to change often so to avoid breaking other classes.
It says that it will never allow Rails to make it available as an action,
Hmm, is this in a Rails Conroller class? And is the book you are working through written for Rails 2.x?
In Rails 2.x, by default any public method in a Controller can be triggered by someone accessing the url /name_of_controller/name_of_method .
But there are some methods in your controller that you don't want anyone on the web to trigger, they weren't intended as 'action methods'. So in Rails 2.x, you mark those as protected or private, something not public. "action method" means a method you intend to be directly triggered via a URL.
In Rails 3.x, routing has generally changed such that only certain methods you explicitly route to are available to be triggered via a URL. However, it might still make sense to mark non-action-methods in a Controller as protected or private so:
It's more clear from skimming the source which methods are action methods and which aren't
As a precaution in case someone changes the routing in such a way that would allow a URL to trigger those methods not intended as action methods
Or for general reasons of code organization that other answers mention, that are not specific to Rails controller classes.
There are several reasons as mentioned above. The interesting thing about this encapsulation in ruby is that it can be violated.
See the "send" method and its brother "public_send".
And for a very common metaprogramming technique that uses this method see:
dynamic finders
I'm currently working on a Rails project, and have found times where it's easiest to do
if object.class == Foo
...
else if object.class == Bar
...
else
...
I started doing this in views where I needed to display different objects in different ways, but have found myself using it in other places now, such as in functions that take objects as arguments. I'm not precisely sure why, but I feel like this is not good practice.
If it's not good practice, why so?
If it's totally fine, when are times that one might want to use this specifically?
Thanks!
Not sure why that works for you at all. When you need to test whether object is instance of class Foo you should use
object.is_a? Foo
But it's not a good practice in Ruby anyway. It'd much better to use polymorphism whenever it's possible. For example, if somewhere in the code you can have object of two different classes and you need to display them differently you can define display method in both classes. After that you can call object.display and object will be displayed using method defined in the corresponding class.
Advantage of that approach is that when you need to add support for the third class or a whole bunch of new classes all you'll need to do is define display method in every one of them. But nothing will change in places where you actually using this method.
It's better to express type specific behavior using subtyping.
Let the objects know how they are displays. Create a method Display() and pass all you need from outside as parameter. Let "Foo" know to display foo and "Bar" know how to display bar.
There are many articles on replacing conditionals with polymorphism.
It’s not a good idea for several reasons. One of them is duck typing – once you start explicitly checking for object class in the code, you can no longer simply pass an instance of a different class that conforms to a similar interface as the original object. This makes proxying, mocking and other common design tricks harder. (The point can be also generalized as breaking encapsulation. It can be argued that the object’s class is an implementation detail that you as a consumer should not be interested in. Broken encapsulation ≈ tight coupling ≈ pain.)
Another reason is extensibility. When you have a giant switch over the object type and want to add one more case, you have to alter the switch code. If this code is embedded in a library, for example, the library users can’t simply extend the library’s behaviour without altering the library code. Ideally all behaviour of an object should be a part of the object itself, so that you can add new behaviour just by adding more object types.
If you need to display different objects in a different way, can’t you simply make the drawing code a part of the object?
Is there some way to acces the user object from a custom routing class?
I'd like to add a parameter when generating a url, and that parameter is inside the user session, so I need to access it.
The only way I found to access is using the sfContext::getInstance()->getUser(), but it's known to be inefficient.
Thanks!
I'd write it the way you mention - I've used that method in similar situations and never had an issue performance wise, and suspect you will be the same.
Also, never heard this mentioned as inefficient, but it is a little bit frowned upon because it couples the route to the context. An alternative that would overcome this would be to pass the variable to the route as you would any other parameter (or the user object if you need the whole thing). If you need to do this a lot, you can always make a custom url helper that wraps the existing url_for method, adding this param to any other details passed.
A workaround I have implemented (for now), is getting some data from somewhere (not ideal, I'm willing to access the user session yet), and set a new parameter inside $params, in the generate method of the custom routing class.
Hope it helps...