12

I'm sure I'm miss understanding the use of call but I thought I could do something like this.

@case_studies = CaseStudy.call("some_named_scope")

Where "some_named_scope" is also a named scope in CaseStudy. The reason why I need to use call is because I have named scopes that are the same names of the actions in the controller so I'm hopping to do something like this.

@case_studies = CaseStudy.call(params[:action])

EDIT

Forgive me, I just realized I was thinking about the send method, some how the word call got stuck in my head. But @case_studies = CaseStudy.send(params[:action]) works as I thought it would.

juliocesar
  • 5,706
  • 8
  • 44
  • 63
Polygon Pusher
  • 2,865
  • 2
  • 27
  • 32

4 Answers4

10

Although @kolrie has the correct answer, it is not safe at all.

It should be whitelisted as follows:

scope = ["first_scope", "second_scope", "default_scope"].include? params[:action] ? params[:scope] : "default_scope"
@case_studies = CaseStudy.send(scope)
BookOfGreg
  • 3,550
  • 2
  • 42
  • 56
9

If some_named_scope is a named_scope of the CaseStudy model, you can use send to call the method corresponding to params[:action] value. But this is obviously heavily exploitable.

So, security aside, you could get going with:

@case_studies = CaseStudy.send(params[:action])

Hope it works.

kolrie
  • 12,562
  • 14
  • 64
  • 98
  • I did upvoted your answer since you have answered first. I got some time to really understand what he was asking. =) – Paulo Henrique Nov 09 '12 at 22:46
  • I appreciate, and yes it is a confusing question. What made me understand was the term "named scope" :-) – kolrie Nov 09 '12 at 22:48
  • when you say this is obviously heavily exploitable could you point me in some direction of a better way of doing something like that? – Polygon Pusher Nov 09 '12 at 23:01
  • 1
    What comes to mind is that you could at least perform a check that ensures that the `params[:action]` is within some expected values. Something like `if %w(approved pending unassigned).include?(params[:action]); ...; end`. – kolrie Nov 09 '12 at 23:12
  • @DigitalCake Pulling this string in from params (i.e. the user or a bot) means they can put essentially whatever they want in there. The best way to go about this is whitelisting your expected values so that nothing out of the ordinary can make it through: http://stackoverflow.com/a/17732753/293280 – Joshua Pinter Apr 13 '15 at 14:20
  • @DigitalCake For something simple like this I would do `raise unless WHITELISTED_NAMED_SCOPES.include?( params[:action] )` – Joshua Pinter Apr 13 '15 at 14:24
1

To have an extra layer of security on top of the whitelisting BookOfGreg suggested, use public_send instead of send, it'll only work calling methods of the public interface, while send can reach even private methods.

So:

CaseStudy.public_send(:some_scope)

fabriciofreitag
  • 2,843
  • 22
  • 26
0

If I understand what you mean, that's what you should call it:

@case_studies = CaseStudy.send(:some_named_scope)

You can use send to call a method and pass either a symbol or a string to it.

BookOfGreg
  • 3,550
  • 2
  • 42
  • 56
Paulo Henrique
  • 1,025
  • 8
  • 12
  • I gave that a try but I maybe missing something. $ CaseStudy.const_get("work"), NameError: wrong constant name work were as CaseStudy.work is a valid scope. – Polygon Pusher Nov 09 '12 at 22:47