Conditionally adding a link to a form -- how?

Try using params instead of variables. The variables lose scope when
changing between views/controllers and once that happens, the value
becomes nil. Instead of
@show_new_expanse_page = true try
params['new_expense_page'] = true

and the value will persist until used. the test for this would be
changed from

<%= link_to 'New Expense', '/expenses/new' if @show_new_expense_page
%> to
<%= link_to 'New Expense', '/expenses/new' if
params['show_new_expense_page'] %>

Bob, I don't understand, a variable @show_new_expense_page set in the
controller will be available in the view.

Colin

Bob, I don't understand, a variable @show_new_expense_page set in the
controller will be available in the view.

Colin

Set where in the controller? In a :before_filter or in show?

It doesn't matter, either will do. Assuming that 'show' is the action
being run.

Colin

Hi Colin,

I had to work on adding authenticated users to my app, so I had to
back-burner the conditional-link issue. I nevertheless would like to
keep trying to learn how to do this. Maybe CSS is the way to make the
link switch between visible or not depending on context. (Just my
inspiration at the moment.)

Also, you mentioned that I needed have my switch initialized to
false, because nil will result in the same thing, so I just
commented it out in VendorController. Seems to clear up one problem.

Your first attempt just above is already a class variable, as it
starts with @ so I don't follow you here.

I think @xxx defines an instance variables while @@xxx defines a class
variable in Ruby. That's what my Ruby books tell me, as does
http://www.rubyist.net/~slagell/ruby/instancevars.html.

It's nice that we got a couple of other respondents. Maybe we'll get
this resolved shortly.

Best wishes,
Richard

You're making this wildly overly complicated.

Stick this in a view file:

<% @foo = "bar" %>
<% @state = false %>
<%= @foo if @state %>

See what appears. Change @state to true and see what appears.

If the variable you're using to eval true/false gives you different and/or
unexpected results, that variable is not what you think it is.

Use debug or inspect or logging to figure out why.

HTH,

Hi Colin,

I had to work on adding authenticated users to my app, so I had to
back-burner the conditional-link issue. I nevertheless would like to
keep trying to learn how to do this. Maybe CSS is the way to make the
link switch between visible or not depending on context. (Just my
inspiration at the moment.)

Also, you mentioned that I needed have my switch initialized to
false, because nil will result in the same thing, so I just
commented it out in VendorController. Seems to clear up one problem.

Your first attempt just above is already a class variable, as it
starts with @ so I don't follow you here.

Yes you are right of course, forgot to engage brain. There is no need
for a class variable, an instance variable is what you want.

Colin

Following up on what Bob Smith posted on 4/21 and Hassan Schroeder on
4/24,
here's what I've got working:

======= app\views\vendors\show.html.erb =====
[snip]
<%= link_to 'Edit', edit_vendor_path(@vendor) %> | <%# From scaffold -
%>
<%= link_to 'Back', vendors_path %> <%# From scaffold -%>

<%# params['show_new_expense_page'] = true %>

<% if params['show_new_expense_page'] -%>
    >
    <%= link_to 'New Expense', '/expenses/new' %>
<% end -%>

<% params['show_new_expense_page'] = false %>

============== end ===================

With the "params ... = true" line commented out, I get two links:
Edit | Back

Un-commented, I get three links as desired, and they all work:
Edit | Back | New Expense

My intention is to have the "New Expense" link visible when a
particular link was previously clicked in the following page:

======= app\views\expenses\new.html.erb =====
[snip]
    <% @current_vendors =
Vendor.find(:all, :order=>"nickname").collect { |v|
      v.nickname + parens(v.qbname) } %>
    <%= f.select :vendor, @current_vendors %>
    <% params['new_expense_page'] = true -%>
    <%= link_to 'New
Vendor', :controller=>'vendors', :action=>'new' %>
[snip]
================= end =================

But the "params ... true" setting is not conveyed to the app\views
\vendors\show.html.erb page.

1. Can this be fixed?
2. If not, will using session rather than params work?
3. Or can I access the "previous page" value in the app\views\vendors
\show.html.erb page and test whether the previous page was app\views
\expenses\new.html.erb?

Again, thanks to all of you for your past responses. I'd be grateful
for any additional ideas you may offer.

Following up on what Bob Smith posted on 4/21 and Hassan Schroeder on
4/24,
here's what I've got working:

======= app\views\vendors\show.html.erb =====
[snip]
<%= link_to 'Edit', edit_vendor_path(@vendor) %> | <%# From scaffold -
%>
<%= link_to 'Back', vendors_path %> <%# From scaffold -%>

<%# params['show_new_expense_page'] = true %>

<% if params['show_new_expense_page'] -%>
>
<%= link_to 'New Expense', '/expenses/new' %>
<% end -%>

<% params['show_new_expense_page'] = false %>

============== end ===================

With the "params ... = true" line commented out, I get two links:
Edit | Back

Un-commented, I get three links as desired, and they all work:
Edit | Back | New Expense

My intention is to have the "New Expense" link visible when a
particular link was previously clicked in the following page:

======= app\views\expenses\new.html.erb =====
[snip]
<% @current_vendors =
Vendor.find(:all, :order=>"nickname").collect { |v|
v.nickname + parens(v.qbname) } %>

Nothing to do with your problem but you should definitely not be doing
finds in the view, this should be in the controller.

<%= f.select :vendor, @current_vendors %>
<% params['new_expense_page'] = true -%>
<%= link_to 'New
Vendor', :controller=>'vendors', :action=>'new' %>
[snip]
================= end =================

But the "params ... true" setting is not conveyed to the app\views
\vendors\show.html.erb page.

1. Can this be fixed?
2. If not, will using session rather than params work?
3. Or can I access the "previous page" value in the app\views\vendors
\show.html.erb page and test whether the previous page was app\views
\expenses\new.html.erb?

The solution has been suggested several times already in this thread,
I will try again.
In the _controller_ method that is rendering the page that has the
conditional link displayed set a variable
@show_new_expense_page = true
at the point in the code where you know that you wish to show the link.
In the view then just use if @show_new_expense_page on the link display.

Please try this and get back if you have problems, or ask for
clarification if you do not understand it (if so which bit do you not
understand). The approach you are trying to use is not the best way.

Colin

forgot to engage brain

The happens to me all the time. I retired a decade ago and I often
can't remember what I did or intended five minutes ago. I've
developed some techniques for combating this weakness, e.g.. when
programming I log screen-shots of what I did and what I got as a
result. It has a two-fold benefit: (1) if something goes awry, I can
accurately recall what led up to the problem; and (2) if I can't
remember how to do something I "know" how to do, I can search my log
mechanically to get a clue.

Cheers,
Richard

I think I see the cause of lack of communication between params in
1) app\views\expenses\new.html.erb; and
2) app\views\vendors\show.html.erb

The are two distinct params, viz:
one in an instance of app\controllers\expenses_controller.rb;
the other in instance of app\controllers\vendors_controller.rb;

And if I we overcome that problem, perhaps there's an even bigger
problem:
my app is intended to be installed on a server, includes the database.
But the app is to be users of several classes on the network.
Wouldn't the use of params fail in that case, but be ameliorated by
use of sessions?

Am I all wet about this?

Thanks in advance,
Richard

RichardOnRails wrote:

forgot to engage brain

The happens to me all the time. I retired a decade ago and I often
can't remember what I did or intended five minutes ago. I've
developed some techniques for combating this weakness, e.g.. when
programming I log screen-shots of what I did and what I got as a
result.

Can I suggest that you supplement this with automated tests and version
control?

It has a two-fold benefit: (1) if something goes awry, I can
accurately recall what led up to the problem; and (2) if I can't
remember how to do something I "know" how to do, I can search my log
mechanically to get a clue.

Cheers,
Richard

Best,

Yes. I think you are totally missing how the Web works :slight_smile:

The params hash represents name/value pairs passed from a client
(browser, typically) to your server, either as a GET request's query
string, or as body parts of a POST request.

So the life of a params hash is one request. If you want something
to persist beyond that, put it in session, store it in the DB or use a
hidden field in a form.

Or copy it into an @ variable in the controller action to make it
available in the rendered view. But I believe for the OP's problem he
does not require to use params (or persistence) at all. See my
previous post.

Colin

My impression is that the OP is trying to set a variable in one view
(and yes, that's the wrong place to do it regardless):

  app\views\expenses\new.html.erb

and have it show up in another:

  "But the "params ... true" setting is not conveyed to the
       app\views\vendors\show.html.erb page."

Hence the issue of persistence...

I believe he has been trying to do that, but is that what he needs to
do? Can he not just set the condition variable in the controller
action? With a parameter on the link calling the action if necessary.

Colin

Not according to the examples provided -- there's a link shown to e.g.
/vendors/new, which would presumably lead to a POST request to a
`create` action, which would then redirect to a new GET request for
/vendor/:id `show` - which is where the OP says he wants that value
available.

You may be right, I did not read as much into the OPs question as you
have. I assumed that _any_ redirect to show from the create should
include the extra link, rather than specifically a create initiated
from the link you mention. If my interpretatioin is correct then he
can just specify a parameter in the redirect_to :action => 'show' in
the create action. If your interpretation is correct (which it may
well be having re-read the original post) then I agree with your
analysis. I would probably put something in the session for this
case.

Over to you Richard - what is your requirement in this regard.

Colin

Hi Colin,

Hi Marnen,

Can I suggest that you supplement this with automated tests and version
control?

Absolutely! That's definitely on my agenda. But this (first) Rails
app is intended to automate a substantial part of burden my son faces
in managing his small business. So, I'm focused on getting "version
1" of this app developed and deployed to prove that "help is on the
way."

Using BDD and Subversion are my goals, but the learning curve for
effective use is time taken from a delivery date. I just spent more
than a week learning how to introduce navigation subtleties into my
app. I probably left this problem for "version 2" but I was annoyed
that my years of 20th Century computer-consulting skills were
inadequate for the 21st Century Web.

Now that I got a glimpse into handling this navigation problem, I off
to work on the last functionality required before version 1
deployment: authenticated users.

With thanks for your interest in my humble efforts,
Richard

Something is still not working as you think it is. An @ variable set
in a controller action only has life into the rendered view from that
action, there should be no need to reset it for another action. I
suggest you use ruby-debug (look at the rails guide on debugging,
google rails guides if necessary) and break into you actions and views
and work out what is going on. Also study the log file to see exactly
what is happening.

I have just seen your next post in reply to Marnen's suggestion on
testing. I suggest you run for cover.

Colin