5-second code syntax question

Hi there,

I have a n00b question regarding the correct code syntax:

The aim is to have code that looks like this...

Tom, where is it that you want to replace low with params[:id]?

Be careful here, depending on your user base of course.

What will you do if {params[:id]} (I know, incorrect syntax), evaluates to “delete!” or something else.

If you have a completely trustworthy user base (such as only you, or only your colleagues, whom you should trust implicitly, otherwise, why would you want to work with them), then once you figure out the right syntax (which probably involves the use of #send, or something like that), you should be fine.

If you are exposing this to the wild world wide web (WWWW), then I would recommend against this.

You would probably be better off writing a helper function that mapped params[:id] into one of the acceptable values. Perhaps something like:

def better_form_of_low(user, id)
case id
when :low
user.low

when :high
user.high
end

and call that with better_form_of_low(@user, params[:id])

just my $.02 from my paranoid mind :slight_smile:

–wpd

Thanks. In this case, the "params[:id]" value is actually a
system-generated one - so there's no user input involved and therefore
it should be secure.

Can you tell my how to get the syntax correct in the above example?

("params[:id]" could of course be replaced by any variable, such as
"@level")

Thanks!

Thanks. In this case, the "params[:id]" value is actually a
system-generated one - so there's no user input involved and therefore
it should be secure.

Can you tell my how to get the syntax correct in the above example?

("params[:id]" could of course be replaced by any variable, such as
"@level")

Ruby is great for calling methods that you don't know the name of
ahead of time. Every object has a "send" method you can call to
dynamically call methods:

method_name = params[:id] # or whatever your case may be
current_value = @user.send(method_name) # call the method

Then you can do whatever you want with that value.

Does this help?

Jeff

purpleworkshops.com
switchingtorails.com

Patrick is 100% right. And he's not even being paranoid, it is almost
guaranteed that someone will try this.

This is how I would do it, and as Patrick suggests, put it in helper:

if (%w(low medium high).include? params[:id]
  instance_variable_set("@#{params[:id]}", user.send(params[:id]))
else
  # somebody is being really naughty, blow up their computer
end

You can then get the instance variable by invoking
instance_variable_get("@#{params[:id]}")

Responses interwoven below.

Quoting Tom Ha <rails-mailing-list@andreas-s.net>:

Well, basically *everywhere* where it says "low" in the below code
example:

The "resulting" code...

  if @user.low == true
    @low = false
  elsif @user.low == false
    @low = true
  end

  [...]

Breaking your question into pieces.

case @user.low
when true
  @low = false
when false
  @low = true
end

This is exactly equivalent to your code above. If all you care about is the
falseness (nil or false) or trueness (anything else), it can be simplified to:

@low = !@user.low

...is supposed to be "generated" by something like this... (which is NOT
yet correct syntax)

==========================
  if @user.{params[:id]} == true
    @{params[:id]} = false
  elsif @user.{params[:id]} == false
    @{params[:id]} = true
  end

This is harder to handle, your syntax is not valid Ruby, so I have to make
some assumptions what you mean. Again breaking into pieces:

@user.{params[:id]} isn't valid Ruby.

If @user is a hash, i.e., it was set with something like:

@user = {1 => 2, 3 => 4}

Then @user[params[:id]] is the proper syntax.

The same is true if @user is derived from ActiveRecord. You will get the
attributes of @user, not the instance variables. Attributes are stored in the
database, instance variables usually aren't (except of course for the values
in the @attributes hash).

If both @user and the current object instance are ActiveRecords, and both are
only true or false and all values of params[:id] are attribute names:

self[params[:id]] = !@user[params[:id]]

If all values of params[:id] are methods, i.e. explicit via "def abc()
... end" or implicit (i.e. accessors, e.g. attr_accessor 'abc') then the
previous example becomes:

self.send(params[:id] + '=', !@user.send(params[:id]])

For most any combination of types, the following is correct:

case @user.send(params[:id])
when true
  self.send(params[:id] + '=', false)
when false
  self.send(params[:id] + '=', true)
end

If "@{params[:id]}" is instance variables without accessors, i.e. private,
someone else will have to answer your question.

HTH,
  Jeffrey