Our Rails projects make heavy use of content_for. However, we quite often need to render default content if nothing is defined using content_for. For readability and maintainability it makes sense for this default content to be in a block.
We made a helper method in Rails 2.3 and we've now refactored this for Rails 3 (as below).
Both those helpers work very well but I'm wondering if there's a more succinct way I could achieve the same thing in Rails 3.
Rails 2.3:
def yield_or(name, content = nil, &block)
ivar = "#content_for_#{name}"
if instance_variable_defined?(ivar)
content = instance_variable_get(ivar)
else
content = block_given? ? capture(&block) : content
end
block_given? ? concat(content) : content
end
which is useful for doing things like this:
<%= content_for :sidebar_content do %>
<p>Content for the sidebar</p>
<% end %>
<%= yield_or :sidebar_content do %>
<p>Default content to render if content_for(:sidebar_content) isn't specified</p>
<% end %>
Refactored for Rails 3:
def yield_or(name, content = nil, &block)
if content_for?(name)
content_for(name)
else
block_given? ? capture(&block) : content
end
end
This can be done entirely in the view using the content_for? method.
<% if content_for?(:sidebar_content) %>
<%= yield(:sidebar_content) %>
<% else %>
<ul id="sidebar">
<li>Some default content</li>
</ul>
<% end %>
Related
This is likely an error due to my minimal understanding of Rails and how to use variables across models, so if there is more code needed to answer it or if my terminology is incorrect, let me know and I will gladly update the question.
I have a feed of posts that I want a user to be able to "like." While the following code allows likes to work on an individual post's page - site.com:3000/posts/*post.id* - with the form data being passed of like[liked_post_id]:*post.id*, when I try to submit a like on a profile - site.com:3000/users/*user.id* - which contains a feed of posts, the form data being passed is like[liked_post_id]: (blank value)
How can I pass the post's ID within a feed of posts to the liked_post_id variable in _like.html.erb?
I have noticed that the action of the like form is /likes across the board. Would this will only work when you are on the page site.com:3000/posts/*post.id*? I'm curious if I need to modify the it so that the action of the form is /posts/*post.id*/likes when you are on the page site.com:3000/users/*user.id*
From my post view:
#views/posts/_post.html.erb:
...
<%= render 'posts/like_form' if signed_in? %>
...
Route to proper form:
#views/posts/_like_form.html.erb:
<div id="like_form">
<% if current_user.likes_this?(#post) %>
<%= render "posts/unlike" %>
<% else %>
<%= render "posts/like" %>
<% end %>
</div>
Like from:
#views/posts/_like.html.erb
<%= form_for Like.new, :remote => true do |f| %>
<%= f.hidden_field :liked_post_id, :value => #post.id %>
<%= f.submit "Like" %>
<% end %>
From profile (feed of posts):
#views/users/show.html.erb
...
<%= render #posts %>
...
Likes controller:
#controllers/likes_controller.rb
class LikesController < ApplicationController
before_filter :signed_in_user
def create
#post = Post.find(params[:like][:liked_post_id])
current_user.like!(#post)
respond_to do |format|
format.html { redirect_to root_url }
format.js
end
end
...
User model:
#models/user.rb
...
def like!(post)
likes.create!(liked_post_id: post.id)
end
...
#frank-blizzard has pointed out that my form markup is an issue. On a post's page the generated markup is:
<input id="like_liked_post_id" name="like[liked_post_id]" type="hidden" value="73" />
While on the feed page:
<input id="like_liked_post_id" name="like[liked_post_id]" type="hidden" />
You can do something like this:
<% form_for Like.new, :remote => true do |f| %>
<%= f.hidden_field :post_id, :value => #post.id %>
<%= f.submit %>
<% end %>
The current_user.likes.build(...) part should get out of your view and inside your controller. You are using a current_user.like! method so I guess you have implemented already some method in user model to accomplish this. If not build your like in the create action of LikesController where you can access params[:like].
def create
#post = Post.find(params[:like][:post_id])
current_user.likes.build(#post)
# ...
end
EDiT
You might need to pass your #post variable correctly into your _like_form partials, like so:
#views/posts/_post.html.erb:
...
<% if signed_in? %>
<%= render 'posts/like_form', :post => #post %>
<% end %>
...
This will give you acceess to a post variable inside the partial so you can prepopulate your forms value with its id. See this questions as well Pass a variable into a partial, rails 3? and make sure to read up on how to pass variables correctly to partials. you can debug your views using <%= debug <variablename> %>
I'm looking for a way to include a specific element at a certain position inside an iteration
Not experienced enough to use the right pattern (hence to search here on stack overflow with the right keywords, afraid of getting some duplicate question with this one)… but the base idea would as the following :
<% Post.all.each do |post| %>
<% if Post.all.index(post) == 5 # or any position %>
# render some html element (some kind of exception)
<% else %>
<%= post.title %>
<% end %>
<% end %>
But just without skipping any records in my post array
I'm not sure I have totally understood your request. each_with_index may help you, and if you don't use the else, you won't skip any records :
<% Post.all.each_with_index do |post, index| %>
<% if index == 5 # or any position %>
# render some html element (some kind of exception)
<% end %>
<%= post.title %>
<% end %>
I am taking a rails class at my University and I am trying to create a search form which will show the results on the same page rather than show a different page of results. Is this something simple to do? I am creating a museum app with artifacts for each museum but I want the user to search artifacts from either page.
On my routes.rb I have
resources :artifacts do
collection do
get 'search'
end
end
On my museum index I have the code below that he gave us but not sure how to tweak the get routes for the same page.
<%= form_tag search_artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
<% if #artifacts %>
<p> <%= #artifacts.length %> matching artifacts. </p>
<h2> Matching Artifacts </h2>
<% #artifacts.each do |a| %>
<%= link_to "#{a.name} (#{a.year})", a %><br />
<% end %>
<% end %>
Yes, this is easy. Just have the index page return the search results if params[:search_text] is present - this way you don't need a new route or a different page.
class ArtifactsController < ApplicationController
def index
#artifacts = Artifact.search(params[:search_text])
end
end
class Artifact < ActiveRecord::Base
def self.search(query)
if query
where('name ILIKE ?', "%#{query}%")
else
all
end
end
end
So then your form looks like:
<%= form_tag artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
Edit:
So what you really want to do is any page you want to search, include a form which makes a request to that same page.
Then in each of those controller methods just put this line of code:
#artifacts = Artifact.search(params[:search_text])
and that will populate the #artifcats array with only artifacts that match the search query.
Try using "Ransack" gem. It can also perform some more powerful searches.
I am developing a facebook app using rails 3 and facebooker2
i cannot find any example on how to use fb_server_fbml helper method.
what is "proc" in its paramter. Can anyone provide me with sample code?
Thanks
The &proc parameter is used as a content block that is inserted between the <fb:serverFbml> tags. You can learn more about block helpers and differences between Rails 2.3 and Rails 3 here: Block Helpers in Rails 3
So, try something like this:
<% fb_server_fbml do %>
<%#Insert here your content %>
<% end %>
If you want to use the request form, try the following:
<% fb_server_fbml do %>
<% fb_request_form("Your app name","http://www.example.com/callback","Try this out!") do %>
<%= fb_multi_friend_selector("Invite your friends:", {:rows => 3}) %>
<% end %>
<% end %>
I would like to render structures like this:
<tag1>
<tag2 someattribute="somevalue">
<.. lot of things inside ..>
</tag2>
</tag1>
<tag1>
<tag2 someattribute="someothervalue">
<.. different inside things inside ..>
</tag2>
</tag1>
The tag1, tag2 are the same, they are just parametrized. The inner part of the code changes. I tried to implement the thing above like that (haml):
%div{id:['products', id]}
.products_content
%div{id:['products', id, 'content'], class:'products_mask'}
= yield
This was the partial _content_head.html.haml, which is called from a template:
= render 'shared/content_head', id: 'all' do
%h3= Title
%p= Body of the text.
My theory that yield inside the partial would lead to rendering of the passed block did not prove. Is there a way to use partials as code wrappers? Can you suggest me some solution how to reach this? Thank you.
This might be a good use of the capture method.
I'm only familiar with ERB, but here is the general idea:
<% structure = capture do %>
<h3>Title</h3>
<p>Body of text</p>
<% end %>
Then pass the variable into the partial:
<%= render 'shared/content_head', :structure => structure %>
And within the partial, spit out the structure variable:
<%= structure %>
Reset structure multiple times within the view as you render partials (or maybe more appropriately, in a helper?).
I've used the following (Rails 4, but I think it should work with Rails 3 too):
<%# app/views/users/_edit.html.erb %>
<%= render layout: 'modal_wrapping' do |f| %>
<%= f.input :email %>
...
<% end %>
.
<%# app/views/users/_modal_wrapping.html.erb %>
<div id='modal'>
<%= simple_form_for #user do |f| %>
<%= yield f %>
<% end %>
</div>