Rails delete_if using hashes to ignore current article (Middleman) revisited - ruby-on-rails

I've got an easy one for you guys.
I want to have a featured content section where the current article link is hidden or removed
So already this works using Middleman Blog with delete_if:
<% blog(content).articles.delete_if{|item| item == current_article}.each do |article| %>
<%= article.href %>
<% end %>
However I'm using Middleman proxies so I don't have access to the current_article method...
I've got an YAML structure that holds the following mock data (amongst others) with the folder setup like: data > site > caseStudy > RANDOM-ID423536.yaml (Generated by a CMS)
Inside each yaml file you'll find stuff like:
:id: 2k1YccJrQsKE2siSO6o6ac
:title: Heyplace
My config.rb looks like this
data.site.caseStudy.each do | id, this |
proxy "/cases/#{this.slug}/index.html", "/cases/cases-template.html", :locals => { this: this }, :ignore => true
end
My template file holds the following
<%= partial(:'partials/footer', :locals => {:content => data.site.caseStudy, :title => 'See more projects'}) %>
My loop that gets content
<% content.each do |id, this| %>
<%= partial "partials/tile" %>
<% end %>
So I guess my question is, how can I use delete_if in this instance so that the current article isnt being displayed?
I have tried stuff like, but to no avail:
<% content.delete_if{|e| e.title == content.title}.each do |id, article| %>
<%= article.href %>
<% end %>
As well as:
<% content.reject{|key, value| key >= this.id }.sort_by{ |index| rand }.each do |id, this| %>
<%= partial "partials/tile" %>
<% end %>
(This deletes the data all together forever until you reload the page, strange!)
Any help is appreciated! Thank you!

Related

rails delete_if using hashes to ignore current article (Middleman)

I've got an easy one for you guys.
I want to have a featured content section where the current article is EXCLUDED
So this works using Middleman Blog with delete_if:
<% blog(content).articles.delete_if{|item| item == current_article}.each do |article| %>
<%= article_content %>
<% end %>
However I'm using Middleman proxies so I don't have access to the current_article method...
I've got an YAML structure that holds the following mock data (amongst others) with the folder setup like: data > site > caseStudy > RANDOM-ID423536.yaml (Generated by a CMS)
Inside each yaml file you'll find stuff like:
:id: 2k1YccJrQsKE2siSO6o6ac
:title: Heyplace
My config.rb looks like this
data.site.caseStudy.each do | id, this |
proxy "/cases/#{this.slug}/index.html", "/cases/cases-template.html", :locals => { this: this }, :ignore => true
end
My template file holds the following
<%= partial(:'partials/footer', :locals => {:content => data.site.caseStudy, :title => 'See more projects'}) %>
My loop that gets content
<% content.each do |id, this| %>
<%= partial "partials/tile" %>
<% end %>
So I guess my question is, how can I use delete_if in this instance so that the current article isnt being displayed?
I have tried stuff like, but to no avail:
<% content.delete_if{|e| e.title == content.title}.each do |id, this| %>
<%= partial "partials/tile" %>
<% end %>
Any help is appreciated! Thank you!
Solved, ended up doing
<% content.reject{ | id, item| item == this }.each do |id, this| %>
<%= partial "partials/tile", :locals => { :this => this, :dir => "/#{this.content_type_id.downcase}/", :secondary => 'View' } %>
<% end %>
Courtesy of #David Litvak
I'm the maintainer of contentful_middleman. Looks like you could just send the this to the partial as local, then iterate through your content and make sure that you exclude the one that matches the id of this.

Connect Multiple Yields in Rails

Rails Newbie. Be gentle. If I need to show more stuff I'll do it.
Trying to insert a newsletter signup block above my footer on a project but didn't make it a partial in the layouts set up.
I have the yield outputting an index from a blog.
Right now it's just saying "false" on my local host.
Is it possible to have multiple yields to different indexes?
Is it possible to insert another page into a layout page?
application.html.erb
<div id="blog">
<%= yield %>
</div>
<div>
<%= content_for?(:newsletter) ? yield(:newsletter) : yield %>
</div>
<div>
<%= render 'layouts/footer' %>
</div>
newsletter.html.erb
<% content_for :newsletter do %>
<h1>Get My Awesome News Letter</h1>
<p>Give me your email and keep up to date on my cat's thoughts.</p>
<%= form_tag('/emailapi/subscribe', method: "post", id: "subscribe", remote: "true") do -%>
<%= email_field(:email, :address, {id: "email", placeholder: "email address"}) %>
<%= submit_tag("Sign me up!") %>
<% end %>
emailapi_controller.rb
class EmailapiController < ApplicationController
def newsletter
render params[:newsletter]
end
def subscribe
gb = Gibbon::Request.new
gb.lists.subscribe({
:id => ENV["MAILCHIMP_LIST_ID"],
:email => {:email => params[:email][:address]}
})
end
end
routes.rb
root to: 'posts#index'
get "/:newsletter" => 'emailapi#newsletter'
post 'emailapi/subscribe' => 'emailapi#subscribe'
You shouldn't need this conditional test:
content_for?(:newsletter) ? yield(:newsletter) : yield
try just:
<%= content_for :newsletter %>
Here's the doc on content_for:
http://apidock.com/rails/v4.2.1/ActionView/Helpers/CaptureHelper/content_for
Ie only show the newsletter if newsletter is present.
The extra yield (if newsletter-content is not present) is repeated from the blog-section above.
You probably shouldn't have duplicate plain yields just the one... everything else should have a name (eg :newsletter)
Also - you seem to be missing an <% end %> in newsletter.html.erb
You should be able to just use another render block. I'm not sure where your newsletter.html.erb lives, but if, for example it lived in a folder such as includes/ you could do something like:
<%= render 'includes/newsletter' %>

Scope of each on rails template

I'm new to rails and I'm trying to build a view that will list the parents and related children
Ex:
Passport has many Visas
I want to list information about the passport and the visas that the passport has.
So I have
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<% end %>
<% end %>
I'm getting the error
undefined method `visa_type' for #Passport:0x000000091b8b28
It looks like rails is trying to find the property visa_type for passport, instead of in visa. How does the scope work within each? Can I force it to access visa_type from visa?
I think you're looking for the fields_for form helper. This will allow you to create fields for the relevant visa attributes. Replace your code sample with the following, and you should be all set.
<% #passport_list.each do |passport| %>
# passportFields
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
You can also iterate over the list as follows:
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
<% end %>
For more information on fields_for, check out the link I added above, and to customize further for your use case, check out the "One-to-many" section.
IMO you should always handle the null case of an object.
Something like this if you use rails (present? is a Rails function)...
<% if #passport_list.present? %>
<% #passport_list.each do |passport| %>
passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<%end%>
<%end%>
<% else %>
<p>Nothing to see here</p>
<% end %>
However if your #passport_list is backed by an ActiveRecord Query, you can handle this in the model/helper/controller by returning the .none query on the model. Note that this differs from an empty array because it is an ActiveRecord Scope, so you can chain AR queries onto it
# scope on AR model
def self.awesomeville
where(country_of_origin: "awesomeville")
end
# method queried in controller
#passport_list = Passport.all
if #passport_list.present?
#passport_list
else
Passport.none
end
# additional filtering in view is now possible without fear of NoMethodError
#passport_list.awesomeville
Whereas a ruby Array would raise an error as it would respond to the Array methods.

Rendering content inside a partial via =yield

I'm creating an application with ruby on rails where I have an items/_item.html.erb. Inside the partial is a yield statement so i can add extra content as needed. In this case, I want to add a specific button to item depending on what view calls partial.
This is what I've tried and it renders the partial, but it does not render the block:
_item.html.erb
<%= yield if block_given? %>
<div>
<%= item.name %>
</div>
someview.html.erb
...
<% render(:partial => 'items/item', :collection => current_user.items do %>
<%= "HELLO" %>
<% end %>
...
I have also tried using content_for and some other stuff with no success. Is there a way to be able to render specific content inside a partial via yield? I'm currently using Rails3
EDIT:
I've found out that it's the :collection hash that makes it impossible insert the block.
Both of this pieces of code work:
<%= render :layout => 'items/item' do %>
Hello world
<% end %>
<%= render :layout => 'items/item', :locals => {:item => current_user.items.first} do %>
Hello world
<% end %>
This means that if i do a .each i could accomplish what I want but it would be ugly code. Anyone know a way around this?
content_for should work fine in this case. Here is the code I just double checked locally.
somewhere.html.erb
<% content_for :foobar do %>
fubar
<% end %>
_item.html.erb
<% if content_for? :foobar %>
<%= yield :foobar %>
<% end %>

How do I run an array through an IF statement in rails?

I am creating an application that highlights user messages from a stream based on whether or not the user has been 'vouched'. It works fine if it's setup for a single author. For example
controller: #vouch = Vouch.last.vouched_user_nickname
view:
<% Twitter::Search.new(params[:id]).each do |tweet| %>
<li>
<%= image_tag tweet.profile_image_url %>
<% if #vouch.include? tweet.from_user %> <div class="flit_message_containerh">
<u> <%= tweet.from_user %></u> <%= linkup_mentions(auto_link(h tweet.text)) %>
<div class="time_ago">
<%= link_to distance_of_time_in_words_to_now(tweet.created_at) , tweet %>
<% else %> <div class="flit_message_container">
<u> <%= tweet.from_user %></u>
<%= linkup_mentions(auto_link(h tweet.text)) %>
<div class="time_ago">
<%= link_to distance_of_time_in_words_to_now(tweet.created_at) , tweet %>
<% end %>
But I'm having trouble doing it for multiple user nicknames.
#vouch = Vouch.find(:all,
:select => "vouched_user_nickname",
:group => 'vouched_user_nickname'
)
Any ideas would be greatly appreciated. I'm a rails noob.
Assuming there isn't a relation between your Vouch model and the Twitter source (I haven't used that gem/plugin yet so I don't know), one solution is to pull all the Twitter entries you want and all the vouches in the controller and do the check in the view.
controller:
#tweets = Twitter::Search.new(params[:id])
#vouches = Vouch.find(:all)
view:
<% #tweets.each do |tweet| %>
<div class="flit_message_container<%=
#vouches.any? { |v| v.vouched_user_nickname == tweet.from_user } ? "h" : ""
%>">
...
</div>
<% end %>
#vouch = Vouch.find_by_vouched_user_nickname(:all, ["nickname1","nickname2"])
Your problem seems to be that you are not looping through the array, so how can it decide if certain elements meet the criteria you set?
Example, in your view:
<% for vouch in #vouch do %>
<% if vouch.include? tweet.from_user %>
<div class="flit_message_containerh">
<u> <%= tweet.from_user %></u> <%= linkup_mentions(auto_link(h tweet.text)) %>
<div class="time_ago">
<%= link_to distance_of_time_in_words_to_now(tweet.created_at) , tweet %>
<% else %> <div class="flit_message_container">
<u> <%= tweet.from_user %></u>
<%= linkup_mentions(auto_link(h tweet.text)) %>
<div class="time_ago">
<%= link_to distance_of_time_in_words_to_now(tweet.created_at) , tweet %>
<% end %>
<% end %>
I see several problems.
The first one is this:
#vouch = Vouch.last.vouched_user_nickname
You are using a variable called #vouch to store a user nickname. That is counterintuitive and will confuse other people reading your code (like myself). Use something like this instead:
#vouch = Vouch.last #on the controller
#vouch.vouched_used_nickname #on the view
This ... eum ... "exotic" naming convention helps confusing yourself when you try to do the "multiple" example:
#vouch = Vouch.find(:all,
:select => "vouched_user_nickname",
:group => 'vouched_user_nickname')
Activerecord's find(:all, ...) will allways return an array of activerecord objects (or an empty array). You seem to be expecting an array of strings. You will allways get Vouches if you do Vouch.find.
The :select part just limits the amount of information these vouches have (they only come with vouched_user_nickname populated. The rest, including their id, is empty, because it is not read from the database).
If you want to have an array of user nicknames you can do it like this:
# note the names. #vouchers in plural, and #nicknames for the user names
#vouchers = Vouch.find(:all, :select => "vouched_user_nickname",
:group => 'vouched_user_nickname')
#nicknames = #vouchers.collect{|v| v.vouched_user_nickname}
Is your problem that you don't know the correct controller code to write to find the #vouch array? Or is it that you don't know what to do with the array once you get it?
view: <% if #vouch.include? tweet.from_user %>
.include? is a method you can call on either a single object or an array of objects if tweet.from_user has an object that is also included in the #vouch array to get the #vouch array in your controller you should:

Resources