Link in controller to my view with Rails - ruby-on-rails

I have a controller and I need to make a link to my view:
#projeto.atividades.each do |a|
#mapa[:tasks] << {
id:a.id,
name:<%= link_to a.descricao, edit_atividade_path(atividade) %>
}
end
a.descricao = the word that I want to be the link.
edit_atividade_path(atividade) = my view.
What is the syntax?

Please try the following:
#mapa[:tasks] << {
id:a.id,
name: view_context.link_to(a.descricao, edit_atividade_path(atividade))
}
Also a point to remember is that in your controller you don't need the <% or %> scriptlets since its already ruby code.

Related

Rails active link styling with turbo frames

I have links made like this:
- #glossaries.each do |g|
%a.{ :href => glossary_path(g), data: { 'turbo_frame': :'entry' } }
= g.title
How can I style active link (active glossary) if result of clicking g.title link is rendered in another frame?
I've tried using helper to give a link some class if current path equal requested path, but it is not working. No 'active' class is given to link:
def current_class?(test_path)
return 'active' if request.path == test_path
''
end
When working with frames current path not showing in browser address bar, so I've tried to force it by data-turbo-action" => "advance". With that browser have current path in address bar, but still link do not have 'active' class..
I write this stimulus controller to handle turbo:click event and make a active state to the clicked element. There is an issue when another turbo:click event handler cancelled the visit, but in this place I don't care about it.
import { Controller } from "#hotwired/stimulus";
export default class extends Controller{
static targets = ['link']
static classes = ['active']
initialize(){
this.handleTurboClick = this.handleTurboClick.bind(this)
}
connect(){
this.element.addEventListener('turbo:click', this.handleTurboClick)
}
disconnect(){
this.element.removeEventListener('turbo:click', this.handleTurboClick)
}
handleTurboClick(event){
this.linkTargets.forEach(target => {
if(target == event.target){
target.classList.add(...this._activeClasses)
}else{
target.classList.remove(...this._activeClasses)
}
})
}
get _activeClasses(){
return this.activeClasses.length == 0 ? ['active'] : this.activeClasses
}
}
<div data-controller="turbo-active-link" data-turbo-active-link-active-class="bg-gray-300 hover:bg-gray-300" data-turbo-frame="main">
link A
link B
</div
The reason why it would not update is because the other frame is navigating while the rest of the page stays the same. To make it show the active navigation link you are going to want to either reload both or use some custom JavaScript. I would rather just reload both sides I would do another turbo-frame around the navigation and the sidepanel like so
<%= turbo_frame_tag "glosarries_index" do %>
... Navigation links would be here but remove the data-turbo-frame it will automatically use the closest parent.
<%= turbo_frame_tag "entry" do %>
...
<% end %>
<% end %>

Getting data out of a select box and passing it into params

I am doing this for a school project and it is not working. :(
How do I get out the selected[petowner_id] from the view and make it usable in a ruby controller?
How do I make the #selected_pet = params([petowner_id]) in the controller that comes in from the view to function? Currently it renders an error message when I try to set it. :(
I am getting very tired of it not working.
The controller from Pets controller
class PetsController < ApplicationController
# GET /pets
# GET /pets.json
def monsters
#Finds the current user
if current_user
#user = current_user
#pets_kept = [] #why?
##petowner = Petowner.find(params[:petowner][:id])
#if(params[:commit])
#end
#monster = "Eeeep"
#mypets=[]
#all_my_pets = #user.petowners
#options value = 2
#params { selected_petowner[petowner_id]}
#selectpet = params{[selected][petowner_id]}
#petowner = Petowner.find_by_id(params[:id])
#pet = Pet.find_by_id(params[:pet_id])
#Find the petowners that the user currently has
##mypets = #user.petowners
#This is my way of doing things in a C++ fashion, I don't get all ruby things
#user.petowners.each do |pet|
##selected_pet = pet.find(params[:selected])
# if pet.hp != 0
# #pets_kept << pet #Dont recall seeing the << before in ruby but for C++ statement used for cout statements
#if pet.select
# #selected_pet = pet.select
#end
end
##selected_pet = Petowner.find(params[:petowner][:selected])
#end
#selected_pet = 1 ##user.petowners.find(params[:id])
#mypets = current_user.petowners.select{|pet| pet.hp !=0}
#raise "I am here"
##selected_pet = #mypets.find(params[:id][:selected])
##mypets = #pets_kept
end
The code from the view that doesn't go back to the controller variable and set it. :(
<select id="petowner_id" name="selected[petowner_id]">
<%= #all_my_pets.each do |pet| %>
<option value="<%= pet.id %>"><%= pet.pet_name %></option>
<% end %>
</select>
Previous step from pets/monsters view that doesn't work at all from previous collection. :(
<%= form_for :petowner, :url => petowner_fights_path(#selected_pet, #pet) do |f| %>
<p>Select a pet <%#= f.collection_select(:petowner, :petowner_id, #user.petowners, :petowner_id, :pet_name) %></p>
<%= render 'monsterinfo' %>
<div class="outer"></div>
<%= f.submit "Fight Selected Monster" %>
<% end %>
You probably want params[:petowner][:petowner_id]. Definitely don't construct the select with html in a view.
By the way, it's really helpful to see all of the params passed in to a controller action. I tend to raise params.to_yaml when I need to do that.

How do I construct an if statement within a MVC View

Hopefully this question is quick and painless
I have a mvc view where i want to display either one of two values depending on an if statement. This is what I have in the view itself:
<%if (model.CountryId == model.CountryId) %>
<%= Html.Encode(model.LocalComment)%>
<%= Html.Encode(model.IntComment)%>
If true display model.LocalComment, if false display model.IntComment.
This doesn't work as I get both values showing. What am I doing wrong?
Your if statement always evaluates to true. You are testing whether model.CountryId equals model.CountryId which is always true: if (model.CountryId == model.CountryId). Also you are missing an else statement. It should be like this:
<%if (model.CountryId == 1) { %>
<%= Html.Encode(model.LocalComment) %>
<% } else if (model.CountryId == 2) { %>
<%= Html.Encode(model.IntComment) %>
<% } %>
Obviously you need to replace 1 and 2 with the proper values.
Personally I would write an HTML helper for this task to avoid the tag soup in the views:
public static MvcHtmlString Comment(this HtmlHelper<YourModelType> htmlHelper)
{
var model = htmlHelper.ViewData.Model;
if (model.CountryId == 1)
{
return MvcHtmlString.Create(model.LocalComment);
}
else if (model.CountryId == 2)
{
return MvcHtmlString.Create(model.IntComment);
}
return MvcHtmlString.Empty;
}
And then in your view simply:
<%= Html.Comment() %>
Aside from Darin's point about the condition always being true, you might want to consider using the conditional operator:
<%= Html.Encode(model.CountryId == 1 ? model.LocalComment : model.IntComment) %>
(Adjust for whatever your real condition would be, of course.)
Personally I find this easier to read than the big mixture of <% %> and <%= %>.
Conditional Rendering in Asp.Net MVC Views
<% if(customer.Type == CustomerType.Affiliate) %>
<%= this.Html.Image("~/Content/Images/customer_affiliate_icon.jpg")%>
<% else if(customer.Type == CustomerType.Preferred) %>
<%= this.Html.Image("~/Content/Images/customer_preferred_icon.jpg")%>
<% else %>
<%= this.Html.Image("~/Content/Images/customer_regular_icon.jpg")%>

Why does Response.Write render but Html.ActionLink does not?

Asp.net Mvc1
On my Views/home/Index.aspx which routes from http://localhost/DefectSeverityAssessmentMvcBeta/
This renders
Response.Write("<a href=\"");
Response.Write(Url.Action("Create", "Registration"));
Response.Write("\">Begin Registration</a>");
But returns a 404 for the address of the link http://localhost/DefectSeverityAssessmentMvcBeta/Registration/Create
while this Does not render or show in view source but doesn't cause any exception:
Html.ActionLink("Begin Registration", "Create", "Registration");
I have a RegistrationController and a /Views/Registration/Create.aspx
The registration controller has breakpoints on Index() and Create() but they are not being hit.
I'm not sure how I would use <%= %> in this scenario because it's inside the following code block:
<% if (ViewData.ContainsKey("user"))
{
if (ViewData.ContainsKey("registered") && (bool)ViewData["registered"] == true)
{
//Html.RouteLink("Resume Assessment", "Assessment", new { controller = "Assessment", action = "Index" });
Response.Write("<a href=\"");
// Html.ActionLink("Resume Assessment", "Index", "Assessment");
Response.Write("\">Resume Assessment</a>");
}
else
{
//Html.RouteLink("Begin", "Registration", new { controller = "Registration", action = "Edit" });
// Html.ActionLink("Begin Registration", "Create", "Registration");
Html.RouteLink("Begin", "Default", new { controller = "Registration", action = "Edit" });
//Response.Write("<a href=\"");
//Response.Write(Url.Action("Create", "Registration"));
//Response.Write("\">Begin Registration</a>");
}
}
else
{ Response.Write("Authentication failed"); }
%>
Are you using <% %> in the HTML for both Response.Write and Html.ActionLink? Try using <%= %> for Html.ActionLink(...);
The added equal sign calls Response.Write behind the scenes thus writing you code to the screen.
Because Html.ActionLink return the string and do not write to the response stream. You need to write to your page using <%= %> or Response.Write();
Response.Write(Html.ActionLink("Begin Registration", "Create", "Registration"));
I was not making use of the ability to use
<% if(x) {%> <%=Html.ActionLink(...)%><% } %>
Thanks to Charles Conway I got it working. Here's the code I wound up with:
<div class="entry">
<% if (ViewData.ContainsKey("user"))
{
if (ViewData.ContainsKey("registered") && (bool)ViewData["registered"] == true)
{ %>
<%=Html.ActionLink("Resume Assessment", "Index", "Assessment") %>
<% }
else
{ %> <%=Html.ActionLink("Begin Registration", "Create", "Registration") %>
<%
}
}
else
{ Response.Write("Authentication failed"); }
%></div>
Are you using an equals sign in your context switch, like this?
<%= Html.ActionLink("Begin Registration", "Create", "Registration"); %>
^--needs equals sign here
If you're not using an equals sign, you have to write directly to the Response object.
As far as the routing errors go, you can check out your routes using Phil Haack's diagnostic tool at http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx.
Anything less than IIS7 requires special configuration for the routing.

How can I collapse this very repetitive Ruby/Rails code?

I've got two small structural issues that I'm not sure how to handle given my relative newbie-ness with RoR.
First issue: In one of my views, I have code that looks like this:
<ul style="list-style-type: circle">
<li><%= #apples.size %> apples</li>
<li><%= #oranges.size %> oranges</li>
<li><%= #bananas.size %> bananas</li>
<li><%= #grapefruits.size %> grapefruits</li>
</ul>
Is it possible to refactor this so that I only need to iterate once over some list of different kinds of fruit, and have the appropriate <li>'s be automatically generated? Edit: I forgot to add that #apples, #oranges, etc., might be nil. Is there an idiomatic way to handle that?
Second issue: In my controller, I have code that looks like this:
#apples = Apple.find(:all)
#apples.each { |apple| apple.do_stuff(:xyz) }
#bananas = Banana.find(:all)
#bananas.each = { |banana| banana.do_stuff(:xyz) }
# ... &c
As you can see, the same operation is invoked many times in exactly the same way. Is there a way to shorten this to something like [Apple.find(:all), ...].each { |fruit| ... } and have that work instead?
Thanks very much for your help!
I'd do this in a helper
def fruit_size(fruit)
list = #fruits[fruit]
return if list.empty?
content_tag(:li, "#{list.size} #{fruit}")
end
And this in the view:
<% ["apples", "oranges", "bananas", .....].each do |fruit| %>
<%= fruit_size(fruit)
<% end %>
In your controller:
#fruits = {}
["apples", "oranges", "bananas", ......].each do |fruit|
#fruits[fruit] = fruit.classify.constantize.find(:all).each {|record|
record.whatever_here
end
end
It makes sense to store all the items in a hash, #fruits, so that you don't have to use instance_variable_get and stuff.
Perhaps you also want to define that array somewhere, so that you don't have to repeat it in the controller and in the view. Let's pretend that you have a fruit model.
class Fruit < ActiveRecord::Base
FRUITS = ["apples", "oranges", "bananas", ....]
end
Then, use Fruit::FRUITS in the view and controller.
For the first part:
#li = ''
[#apples, #oranges, #bananas, #grapefruit].each{|fruit|
#li << "<li>#{fruit.size}</li>"}
<ul style="list-style-type: circle">
<%=#li%>
</ul>
You can actually do it pretty simply.
In your controller:
def whatever
#fruits = {
:apples => Apple.find(:all).each{ |a| a.do_stuff(:xyz) },
:bananas => Banana.find(:all).each{ |a| a.do_stuff(:xyz) } # ...
}
end
In your view:
<% #fruits.each |k, v| %>
<li><%= v.nil? ? 0 : v.size %> <%= k.to_s %></li>
<% end %>
Although you might want to consider whether do_stuff is something that could be done via a more complex finder, or by named scope.

Resources