On every page we have a condition like this for guest user.
<% if not_guest? %>
<% link_to "show", path %>
<% end %>
<% if not_guest? %>
<% link_to "delete", path %>
<% end %>
<% if not_guest? %>
<% link_to "edit", path %>
<% end %>
for which link should appear or not for guest user.
Are there any better ways to handle this scenario instead of writing the conditions for every link ?
Make a helper:
#helpers/application_helper.rb
def link_to_unless_guest(*args)
if not_guest
link_to(*args)
end
end
Then call like
<% link_to_unless_guest "show", path %>
def link_to_editable(*args)
options = args.extract_options![:parent]
html_tag = options.nil? ? nil : options.delete(:html_tag)
if not_guest
unless html_tag.nil?
content_tag html_tag,options do
link_to(*args)
end
else
link_to(*args)
end
end
end
<%= link_to_editable 'Show', path,:parent => {:html_tag => "li",:style => "border-top:1px solid #A2A2A2;",:class => "left"} %>
<%= link_to_editable 'Show', path %>
Modified helper which is provided by #Max as per my need.
Related
I tried to make an edit for ruby on rails, but it shows me the argument error about the edit. I am confused about this question.
Then, I have tried to put the different argument into index.html.erb However, it still does not work. For example m.id and m
This is index.html.erb
<% #methodtypes.each do|m| %>
<tr>
<td><%=m.name %></td>
<td><%=m.desp %></td>
</tr>
<%= link_to "Edit", edit_method_types_path(m.id) %>
<% end %>
<%= link_to "Create Method", new_method_types_path %>
This is my controller file:
class MethodTypesController < ApplicationController
def index
#methodtypes = MethodType.all
end
def show
#methodtype = MethodType.find_by_id(params[:id])
end
def create
#methodtype = MethodType.new(method_params)
#methodtype.save
if #methodtype.save
redirect_to method_types_path
else
render :new
end
end
def edit
#methodtype = MethodType.find_by_id(params[:id])
end
def new
#methodtype = MethodType.new
end
private
def method_params
params.require(:method_type).permit(:name, :desp)
end
This is my edit page which is edit.html.erb:
<%= form_for #methodtype do |f| %>
<div>
<%= f.label :name %>
<%= f.text_area :name %>
</div>
<div>
<%= f.label :desp %>
<%= f.text_field :desp %>
</div>
<%= f.submit %>
<% end %>
The result should show that I can edit my text. but, it shows the ArgumentError in MethodTypes#edit. Does someone can give me some suggestion, I do not know how to fix that.....
Wrong edit url path
It should be <%= link_to "Edit", edit_method_type_path(m.id) %> instead of <%= link_to "Edit", edit_method_types_path(m.id) %>
Also check your routes file It seems you are defining
resource: method_types
Change to
resources: method_types
<%= link_to "Edit", edit_method_types_path(m.id) %> should be <%= link_to "Edit", edit_method_type_path(m) %>, note that type is in singular.
Run rails routes -g method_type to confirm it.
Also, change the MethodType.find_by_id(params[:id]) to MethodType.find(params[:id]) in the controller.
Btw, you are calling save twice in your create method:
def create
#methodtype = MethodType.new(method_params)
#methodtype.save # delete this line
if #methodtype.save
redirect_to method_types_path
else
render :new
end
end
I'm using the acts_as_votable gem to like and unlike "Deals" in my Ruby on Rails project. My user is set to act_as_voter and my deal is set to acts_as_votable, but for some reason everything is set to like as soon as a new user is created, and they can't unlike the deal. For some reason my list of deals all have an unlike button and it doesn't actually do anything but refresh the page. Here's some of my code.
app/views/catalog/index.html.erb
<ul class="deals_list">
<% #deals.each do |deal| %>
<li>
<div>
...
<div class="favorite">
<% if account_signed_in? and current_account.accountable_type == "Personnel" %>
<%= image_tag("dark-favorite.png") %>
<% if deal.liked_by current_account %>
<%= link_to unlike_deal_path(deal), method: :put do %>
Unlike
<% end %>
<% else %>
<%= link_to like_deal_path(deal), method: :put do %>
Like
<% end %>
<% end %>
<% end %>
</div>
</li>
<% end %>
</ul>
app/controllers/deals_controller.rb
def like
#deal = Deal.find(params[:id])
#deal.liked_by current_account
redirect_back(fallback_location: catalog_index_url)
end
def unlike
#deal = Deal.find(params[:id])
#deal.unliked_by current_account
redirect_back(fallback_location: catalog_index_url)
end
config/routes.rb
resources :deals do
member do
put 'like', to: "deals#like"
put 'unlike', to: "deals#unlike"
end
end
Be sure and read the entire Readme because you're using the library wrong.
To check if a voter has voted on a model, you can use voted_for?. You can check how the voter voted by using voted_as_when_voted_for.
I zeroed in on your problem because I was expecting to see a "?" after the deal.liked_by call, which would indicate a boolean result (by convention, not always the case).
So use this instead:
<% if current_account.voted_for? deal %>
Seriously, I have no idea where to start. How do I implement a helper breadcrums without using gems?
I tried some gems, but I preffer make a simple helpe. Exist someone or some tutorial? I not found this =/
Thanks!
My solution:
navigation_helper.rb
module NavigationHelper
def ensure_navigation
#navigation ||= [ { :title => 'Home', :url => '/' } ]
end
def navigation_add(title, url)
ensure_navigation << { :title => title, :url => url }
end
def render_navigation
render :partial => 'navigation', :locals => { :nav => ensure_navigation }
end
end
_navigation.html.erb
<ol class="breadcrumb">
<% nav.each do |n| %>
<% unless n.equal? nav.last %>
<li><%= link_to n[:title], n[:url] %></li>
<% else %>
<li><%= n[:title] %></li>
<% end %>
<% end %>
</ol>
application.html.erb
<%= render_navigation %>
And any view:
<% content_for :title, 'My Page Title' %>
<% navigation_add #something.anything, '#' %>
You cant do this.
In your application_helper:
def breadcrumb(&block)
content_tag :ol, { :class => "breadcrumb", :itemprop => "breadcrumb" } do
block.call
end
end
def breadcrumb_item(name = nil, url = nil, html_options = {}, &block)
if name or block
html_options[:class] = "#{html_options[:class]} active" unless url
content_tag :li, html_options do
if block
block.call name, url
else
url ? link_to(name, url) : name
end
end
end
end
Now in views you paste this: (I used index_path and #user.name) - you can paste this code on show view as an example
<%= breadcrumb do %>
<%= breadcrumb_item "index", index_path %>
<%= breadcrumb_item #user.name %>
<% end %>
Now when you need some breadcrumb you can just call this trunck above and change the path and the instance variables #your_variable
I further worked on Elton Santos's solution and decided breadcrumbs should be automatic like history. So I modified some code:
In my application.html.erb
<%= render_navigation %>
In my views, I was already using:
<% content_for :heading do 'User Detail' end %>
So, my navigation_helper.rb look like:
module NavigationHelper
def navigation_add(title, url)
nav_list = session['navigation'].present? ? session['navigation'] : []
nav_list << { 'title' => title, 'url' => url }
# 1. Take last 3 items only (-1 is last, not -0)
nav_list = nav_list[-3..-1] if nav_list.length > 3
# 2. Now, if first is pointing root, remove it
nav_list.shift if nav_list[0]['url'] == '/'
# 3. If last one is same as its predecessor, remove it
nav_list.pop if nav_list.length > 1 && (nav_list[-1]['url'] == nav_list[-2]['url'])
session['navigation'] = nav_list
end
def render_navigation
render partial: 'shared/navigation', locals: { nav_list: session['navigation'] }
end
end
and finally, _navigation.html.erb:
<ol class="breadcrumb">
<li><%= link_to '/' do %>
<i class="fa fa-home"></i> Home <% end %>
</li>
<i class="fa fa-angle-double-right" style="color: #ccc; padding: 0 5px;"></i>
<% nav_list.each_with_index do |nav, i| %>
<% if i != nav_list.length-1 %>
<li><%= link_to nav['title'], nav['url'] %></li>
<% else %>
<li class="active"><%= nav['title'] %></li>
<% end %>
<% end %>
</ol>
So, what's going up here is; I save every page title in session and build breadcrumbs from that. I keep recent three entries only along with hard-coded one for Home and remove duplicate entries when they are not apart.
In my view, I am doing this:
<% case #post
when #post.has_children? %>
<% #post.children.each do |child| %>
<li><%= link_to child.title, post_path(child)%></li>
<% end %>
<% when #post.has_siblings? %>
<% #post.siblings.where.not(id: #post.id).each do |sibling| %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<% end %>
<% when !#post.parent.nil? %>
<li><%= link_to #post.parent.title, post_path(#post.parent) %></li>
<% else %>
</ul>
</p>
<p>
There are no related posts.
</p>
<% end %>
Basically what I want to do is I want to check #post for a variety of conditions. If it has_children?, if it has_siblings?, etc.
I don't want the statement to exit if any of the above is true or false.
Once the view loads, it should automatically check for all of these statements. If it finds any of the above true, it should execute the command right below the check.
The issue is when I do this, it always defaults to the else. i.e. the case statement doesn't work.
I know I could simply just do a bunch of disjointed if statements, but then the HTML around it gets a bit weird.
Is there a way I can do this with a CASE statement?
Edit 1
The reason the if statement doesn't work properly, is if I have 3 if statements back to back - none of which that interact with each other (that's the only way to cycle through all of the conditions properly), is that the else doesn't trigger properly.
E.g. if the first two conditions are true, but the third is not...it will print out "there are no related posts"...when that's not the case. It is the case that there are no parent posts.
Basically I just want to have a catch-all related posts, so I am simply iterating through all of the various options and checking to see if those relations exist. If they do, I am pulling them out and if they don't then they move on. If none exist, then I don't print "there are no related posts".
The fact that the view is already looking looking complex is a sign that it may be a good idea to refactor the logic out of the view and place it into the Post model where it belongs. Ideally the view(s) should end up looking like this:
<%# posts/show.html.erb %>
<% if #post.has_related_posts? %>
<%= render partial: 'children', collection: #post.children, as: :child %>
<%= render partial: 'siblings', collection: #post.other_siblings, as: :sibling %>
<%= render partial: 'parent', locals: {parent: #post.parent}%>
<% else %>
<p>There are no related posts</p>
<% end %>
The paritals:
<%# posts/_children.html.erb %>
<li><%= link_to child.title, post_path(child)%></li>
<%# posts/_sibling.html.erb %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<%# posts/_parent.html.erb %>
<% unless parent.nil? %>
<li><%= link_to parent.title, post_path(parent) %></li>
<% end %>
Then the Post model can organize the logic:
class Post < ActiveRecord::Base
def has_related_posts?
!children.to_a.empty? || !other_siblings.to_a.empty? || !parent.nil?
end
def children
self.children || [] # Rails does this automatically, but just for the example
end
def other_siblings
self.siblings.where.not(id: self.id)
end
#...
end
I know this doesn't directly answer your question, however IMHO I think it's a better solution.
You have two options here.
Use IF ELSIF
<% if #post.has_children? %>
<% #post.children.each do |child| %>
<li><%= link_to child.title, post_path(child)%></li>
<% end %>
<% elsif #post.has_siblings? %>
<% #post.siblings.where.not(id: #post.id).each do |sibling| %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<% end %>
<% elsif !#post.parent.nil? %>
<li><%= link_to #post.parent.title, post_path(#post.parent) %></li>
<% else %>
</ul>
</p>
<p>
There are no related posts.
</p>
<% end %>
Use only case as doz mentioned
<% case
when #post.has_children? %>
<% #post.children.each do |child| %>
<li><%= link_to child.title, post_path(child)%></li>
<% end %>
<% when #post.has_siblings? %>
<% #post.siblings.where.not(id: #post.id).each do |sibling| %>
<li><%= link_to sibling.title, post_path(sibling)%></li>
<% end %>
<% when !#post.parent.nil? %>
<li><%= link_to #post.parent.title, post_path(#post.parent) %></li>
<% else %>
</ul>
</p>
<p>
There are no related posts.
</p>
<% end %>
You can do it with a case statement. Just give case no parameter. Eg instead of case #post just use case
This is the equivalent of an if statement. And should work for what your trying to achieve
Check out ruby case statements for some examples
How can you pass all parameters to a controller action?
# instead of:
<%= link_to mylist_url(id: params[:id], se: "true", st: params[:st], re: params[:re], li: params[:li]) do %> ... <% end %>
# something like:
<% link_to mylist_url(params: :all, se: "true") do %> ... <% end %>
Can you just use Hash#merge?, something like:
<% link_to mylist_url(params.merge(:se=>"true")) do %> ... <% end %>