CASE WHEN Menu based off of Routes.rb and Request.path - ruby-on-rails

I have a case when clause where based on the URL that you're at, it will bring in different menu options. However, depending on some of the menus that you could be at, it doesn't recognize that you have some variables assigned. The system errors:
ActionController::RoutingError in Pages#users_page
Showing /home/initiald/RubymineProjects/SOWOnline/app/views/layouts/_navigation.html.erb where line #27 raised:
No route matches {:controller=>"results", :action=>"show"}
Here is the code that I have so far
<% case request.path %>
<% #ROOT AND SETTINGS %>
<% when '/', settings_path, '/guest' %>
<% #SURVEY AND RESULTS %>
<% when '/sow_survey', '/surveys', '/results', result_path, results_path, available_surveys_path, take_survey_path, view_my_survey_path, edit_my_survey_path %>
<% if permitted_to? [:admin, :partner, :employee], :users %>
<%= link_to 'new survey', available_surveys_path %>
<%= link_to 'edit survey', results_path %>
<% end %>
<% #USERS %>
<% when '/register' , '/users', '/sow_users', edit_user_path %>
<% if permitted_to? [:admin, :partner, :employee], :users %>
<%= link_to 'new user', register_path %>
<%= link_to 'list users', list_users_path %>
<% end %>
<% else %>
<% end %>

There is no any result_path without attributes, but there is result_path(result_id) path, which is:
{:controller=>"results", :action=>"show", :id => your_paticular_id}
and looks like
/results/:id
UPD
Just use regular expression here:
<% when '/sow_survey', '/surveys', '/results', /\/results\/\d*/, results_path, available_surveys_path, take_survey_path, view_my_survey_path, edit_my_survey_path %>
And yes - your code is messy.

Related

How do I create this link_to conditional in a DRY way?

I want to do the following:
<% if current_user.has_role? :demo %>
<%= link_to profile_path(#selected_profile) do %>
<% else %>
<%= link_to profile_path(profile) do %>
<% end %>
What's throwing it off is the beginning of the block in the link_to, within the if statement.
So how do I achieve this without having to duplicate ALL of the code within this if block twice?
Edit 1
This is the error I get from the above code:
SyntaxError at /
syntax error, unexpected keyword_else, expecting keyword_end
'.freeze; else
^
You can do it like this:
<% chosen_profile = current_user.has_role?(:demo) ? #selected_profile : profile %>
<%= link_to profile_path(chosen_profile) %>
So this will not repeat your link_to tag which you need to do. As you have to redirect to the same path and just change the profile object then this will work. You may change the ternary to if else block if the line seems very long and not readable.
And as everyone mentioned that don't use a do after link_to until you need a block. So that will fix your error.
You can achieve this by defining method in you user.rb (Model)
def demo?
self.has_role?("demo")
end
Then you write in your view
<% if current_user.demo? %>
<%= link_to profile_path(#selected_profile) %>
<% else %>
<%= link_to profile_path(profile) %>
<% end %>
This may help you.
do should have end.
Here is the Ruby Doc reference for link_to
Here is more about do in Ruby
<% if current_user.has_role? :demo %>
<%= link_to profile_path(#selected_profile) do %>
selected profile
<% end %>
<% else %>
<%= link_to profile_path(profile) do %>
profile
<% end %>
<% end %>
You are getting error because of do, you are opening the block but not closing it, try this code
<% if current_user.has_role? :demo %>
<%= link_to 'Profile', profile_path(#selected_profile) %>
<% else %>
<%= link_to 'Profile', profile_path(profile) %>
<% end %>
or, you can do it in controller instead
#selected_profile = current_user.has_role?(:demo) ? #selected_profile : profile
and then in the view,
<%= link_to 'Profile', profile_path(#selected_profile) %>
Hope that helps!

Ruby on Rails: one check_box for several submit_tag

I need to have one check_box for several purposes.
For example: I have a list of files. User can choose some of them to be deleted or analysed.
I have the following code but it accepts only one submit_tag "Delete selected".
<% if #files%>
<%= form_tag destroy_multiple_files_path, method: :delete do %>
<%= submit_tag "Delete selected" %>
<% #files.each do |file| %>
<% if (arraydb.file=="no") %>
<p><td> <%= check_box_tag "files[]", file.id %></td><%= file.name %></p>
<% else %>
<div class="my_profile_info">
<p><td> <%= check_box_tag "files[]", file.id %></td> <%= file.name %></p>
<td class="Info">
Info
</td>
</div>
<% end %>
<%end%>
<%end%>
<%else%>
<%end%>
I would like to have submit_tag "Analyse" as well.
I tried something like this but of course it did not work.
<% if #files%>
<%= form_tag destroy_multiple_files_path,analyse_multiple_files_path method: :delete,method:post do %>
<%= submit_tag "Delete selected" %>
<%= submit_tag "Analyse" %>
<% #files.each do |file| %>
<% if (arraydb.file=="no") %>
<p><td> <%= check_box_tag "files[]", file.id %></td><%= file.name %></p>
<% else %>
....
routes.rb:
resources :files do
collection do
delete 'destroy_multiple'
end
end
controller:
def destroy_multiple
#files = File.find(params[:files])
#files.each do |item|
item.destroy
end
end
Thanks in advance.
You can indeed have multiple submit buttons, you just have to give them names:
<%= submit_tag "Delete selected", :name => 'delete' %>
<%= submit_tag "Analyse", :name => 'analyse' %>
You can then check what the commit param contains in the controller and act accordingly:
if params[:commit] == 'delete'
# delete things
elsif params[:commit] == 'analyse'
# analyse things
end
The rest of the form will be submitted as usual.
this worked for me:
<%= form_tag destroy_multiple_files_path, method: :get do %>
<%= submit_tag "Delete selected", :name => 'delete' %>
<%= submit_tag "Analyse", :name => 'analyse' %>
controller:
if params[:commit] == 'Delete selected'
# delete things
elsif params[:commit] == 'Analyse'
# analyse things
end
routes.rb:
resources :files do
collection do
get :destroy_multiple
end
end

Path helpers in a loop

I have a Foo that :has_many Bars. GET Foo#index shows all of the Bars. View looks like this:
<% #foos.each do |foo| %>
<% foo.bars.each do |bar| %>
<%= link_to 'Download', download_bar_path %>
<%= link_to 'New', new_bar_path( :foo => foo.id ) %>
<% end %>
<% end %>
There is a def download in Bars controller and a route:
resources :bars do
member do
get 'download'
end
end
rake routes shows
download_bar GET /bars/:id/download(.:format) {:action=>"download", :controller=>"bars"}
and URL /bars/1/download really works, but the first link in the view (download_bar_path) doesn't. It says No route matches {:action=>"download", :controller=>"bars"}.
What can be the problem?
<% #foos.each do |foo| %>
<% foo.bars.each do |bar| %>
<%= link_to 'Download', [:download, bar] %>
<%= link_to 'New', [:new, :bar] %>
<% end %>
<% end %>
You didn't specified the bar to download, you need to add it by changing this line
<%= link_to 'Download', download_bar_path(bar) %>

Stuck Understanding Link_to

I'm really struggling to understand how to link_to a parent from with a loop.
My milestones belong_to my orders and my orders have many milestones.
In my orders index, I have a simple calendar (table_builder) which lists all my milestones.
<%= calendar_for #milestones, :year => #date.year, :month => #date.month do |t| %>
<%#= calendar_for(#orders, :year => 2009, :month => 1) do |t| %>
<%= t.head('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday') %>
<%= t.day(:day_method => :milestone_due) do |date, orders| %>
<%= date.day %>
<ul>
<% for milestone in orders %>
<li><%= link_to milestone.name, order_path %> </li>
<% end %>
</ul>
<% end %>
<% end %>
This all works swimmingly well but the link doesn't work - I need it to link back to the parent order, not the milestone. It's driving me crazy now!
In my controller, I tried putting:
#milestoneorder = Order.find(params[:id])
But that says it can't find an order without an id.
I'm obviously missing something really basic here.
You need to tell order_path which Order to link back to:
<%= link_to milestone.name, order_path(milestone.order) %>
You could probably just shorten it to this too:
<%= link_to milestone.name, milestone.order %>
UPDATE
If there's a chance some of your milestones don't have orders, you can try something like this:
<% if milestone.order %>
<%= link_to milestone.name, order_path(milestone.order) %>
<% else %>
<%= milestone.name %>
<% end %>
It doesn't sound like you have a route setup for order.
In the routes.rb file
resources :orders
or if you do, you aren't passing in an id for the order.
link_to "link text", order_url(:id => #order)
link_to "link text", order_url(#order) # <== shortened
lastly, the problem may be that order is nil. If it is nil, you will also get the 'can't find route' error.
UPDATE
<% orders.each do |order| %>
<li><%= link_to milestone.name, order_path(order) %> </li>
<% end %>
UPDATE 2
The problem is in the names. I think that you are getting get milestones from t.day not orders.
<%= t.day(:day_method => :milestone_due) do |date, milestones| %>
<%= date.day %>
<ul>
<% for milestone in milestones %>
<li><%= link_to milestone.name, order_path(:id => milestone.order_id) %> </li>
<% end %>
</ul>
<% end %>

How do I manage if-then explosion in view files?

I apologize if this doesn't follow good question guidelines, but I hope it's well in class with How to Manage CSS Explosion and receives a similarly helpful response.
I'm familiar with some basic view prolixity mitigation strategies such as the following:
Use helpers where appropriate
Don't repeat yourself
Use partials and layouts
Feel free to suggest something if I'm missing some big idea in the above list.
Nevertheless, I still end up with having several dimensions/degrees of freedom in my view, causing a lot of if-then statements or at least ternary blocks. For instance, in something I'm currently messing with, I'm working on a header bar for a program where the view is called when three "big" variables:
Whether the user is admin
Whether the user is logged in
Whether the page being viewed belongs to the user or someone else
It ends up looking like this mess:
<% content_for :subheader do %>
<div class="row">
<% if #user %>
<% if #user == current_user %>
<%= link_to 'My programs', user_programs_path(current_user), :class => 'active' %>
<% else %>
<%= link_to "#{#user.username}'s programs", user_programs_path(#user), :class => 'active' %>
<% end %>
<%= link_to 'Browse all programs', programs_path %>
<% else %>
<% if current_user %>
<%= link_to 'My programs', user_programs_path(current_user) %>
<% end %>
<%= link_to 'Browse all programs', programs_path, :class => 'active' %>
<% end %>
<%= link_to 'New Program', new_program_path, :class => 'admin' if current_user.admin? %>
</div>
<% if #regions %>
<div class="row second">
<%= link_to 'Regional program search', request.fullpath, :class => 'active' %>
</div>
<% end %>
<% end %>
Ugly. Readable and easily accessible, but ugly. Some suggestions?
Between experience and new technologies like LESS, I've become pretty good at slimming down my CSS files, but I'm still running into explosion issues with my MVC views.
I would use helpers and model definitions to dry up your code:
class User
def possesive
self == current_user ? 'My' : "#{username}'s"
end
end
module ...Helper
def user_program_link user
if user
link_to "#{user.possesive} programs", user_programs_path(user), :class => 'active'
elsif current_user
link_to 'My programs', user_programs_path(current_user)
end
end
end
You can then simplify all the if statements for the user_program_path calls to this:
<%= user_program_link #user %>
Which would reduce your view code to:
<% content_for :subheader do %>
<div class="row">
<%= user_program_link #user %>
<% if #user %>
<%= link_to 'Browse all programs', programs_path %>
<% else %>
<%= link_to 'Browse all programs', programs_path, :class => 'active' %>
<% end %>
<%= link_to 'New Program', new_program_path, :class => 'admin' if current_user.admin? %>
</div>
<% if #regions %>
<div class="row second">
<%= link_to 'Regional program search', request.fullpath, :class => 'active' %>
</div>
<% end %>
<% end %>
Continue this process to DRY up the rest of your code as well.
Rewrite the view code as follows:
<% content_for :subheader do %>
<div class="row">
<% if #user || current_user %>
<%= link_to ((current_user == #user or #user.nil?) ? "My programs" :
"#{#user.username}'s programs"),
user_programs_path(#user || current_user),
:class => 'active' %>
<% end %>
<%= link_to 'Browse all programs', programs_path,
:class => (#user ? '' : 'active') %>
<%= link_to 'New Program', new_program_path, :class => 'admin' if current_user.admin? %>
</div>
<% if #regions %>
<div class="row second">
<%= link_to 'Regional program search', request.fullpath, :class => 'active' %>
</div>
<% end %>
<% end %>

Resources