Couldn't find Post without an ID - ruby-on-rails

I am trying to get my posts tagged with a certain tag to render. My code in the view is
Views/posts/sports.html.erb
<% my_posts = post.find_by_tag("sports") %>
<%= my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>
my controller for this looks like
def sports
#posts = Post.paginate(:page => params[:page], :per_page => 10)
#post = Post.find(params[:id])
#title = "Newest"
respond_to do |format|
format.html
format.json { render :json => #users }
end
end
I know I have to define the #post variable but I'm not sure what to define it as.
UPDATE
The problem I'm having is a "Couldn't find Post without an ID" error
Second UPDATE
def find_by_tag name
Tag.find_by_name(name).posts
end

Part of the problem, based on what is shown here, is that you are defining instance variables with Post object(s) in the controller, and then not using them for anything in the view. To retrieve a collection of all the posts tagged "sports," you'd do the following in the controller:
#sports_posts = Post.find_by_tag("sports")
and in the view:
<% #sports_posts.each do |post|
etc...
To add pagination, you can just chain that method to the original:
#sports_posts = Post.find_by_tag("sports").paginate(:page => params[:page],
:per_page => 10)
This is different from your snippet, where you define a #posts variable that returns a collection of 10 Post objects, and #post which simply finds a post object based on the id passed by the submitting form params. My guess is that this controller action is not getting created by a form submission, so no params are passed, and therefore params[:id] is nil, hence the error messages you see. In any event, unless you need either of those items in your view (and there's nothing here to suggest they're being used for anything), there's no reason to create them.
What you do need is a collection of posts tagged "sports", which is what the call above accomplishes. It looks like you are trying to do that with post.find_by_tag("sports") in the view. The problem is that you are calling the find_by_tag method on post, which doesn't exist. Post exists - that's the Post class, and probably what you mean to be calling. Just changing post to Post would probably get you where you want, but content retrieval and presentation are better separated if you create your objects in the controller and then use the view to simply render their attribute data (per the example above).

You don't say what's going wrong, you only say what you're trying to do.
A few things to help debug whatever it is you are seeing:
<%= debug(params) if Rails.env.development? %>
In your main layout, this will dump the params hash and may lend a clue.
Also,
rake routes
Make sure you are looking for the right parameter key(s).
In the snippet you provided, you have an equals in front of the my_posts.each ... line, I am not an ERB expert, but I would think you would not want that, instead this:
<% my_posts = post.find_by_tag("sports") %>
<% my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>

Related

Generate method dynamically using strong params in Rails

Is it possible to generate a dynamic method using the strong parameter I get from my view?
In my view I will generate a different path according to the card the user clicks on. Then, in the controller I want to generate a dynamic method using the parameter obtained from the view, but I'm not sure how to write that. Thanks!
show.html.erb
<div class="branch-names">
<% #branches.each do |branch| %>
<div>
<%= image_tag "cat.jpeg" %>
<%= link_to "#{branch.name} Posts", send("#{branch.branch}_posts_path") %>
</div>
<% end %>
</div>
posts_controller.rb
def self.define_category(name)
define_method(name) do |params[:id]|
#posts = Post.where(category_id = params[:id])
end
end
define_category("#{params[:id]}")
You shouldn't define method based on user input. It may cause security issue, and for sure it causes performance penalty related to method cache invalidation.
Instead you can create one method that have an alternarive on params[:id] and then decide what to show to the user:
class MyController
def branches
case params[:id]
when('cat')
do_cat_stuff
when('dog')
do_dog_stuff
end
end
end
For having routes like /posts/cats you do not have to add dynamic methods. Think of branch like of an id of category:
routes:
resources :post_categories, only:[:index, :show]
view:
...
<%= link_to "#{branch.name} Posts", post_category_path(branch.branch) %>
PostCategories controller:
def show
#posts = Post.where(category_id: params[:id])
end
Also you can make posts a nested resource under categories and use a more RESTful structure with /post_categories/some_branch/posts mapping to posts#index

How to show items which belong to the category

I'd like to answer what I'm doing wrong. So, I'm trying to list all products that belong to the category, on the category's page. Here is the code:
<% #product = Product.all%>
<% #product.where("category_id = ?", params[:#category_id]).each do |product| %>
<%= product.title %>
<%end%>
But there is nothing showing up on my page. So, what's wrong?
There is a whole bunch of problems with your code.
1) Read guides for starters.
2) You have to define an instance variable in controller's action, and then in view just use this variable in your loop. I assume, it is index action you have view for. If so,
def index
# this variable will be used in view
#products = Product.where(category_id: params[:id])
end
and then in view
#products.where(category_id: params[:category_id]).each..
Also, Make sure you have in params what you expect (inspect the params if not sure).
3) You do not execute code, so nothing is being output.
In erb to make things being evaluated you either use - or =. You used none of these. Here is how it should look like:
# notice dash at the beginning of the line
<%- #products.each do |product| %>
<%= product.category_id %>
<% end %>
probably you want read :category_id from params, not :#category_id (so it should be params[:category_id], not params[:#category_id]).

How to render the index view, from inside a view in ruby-on-rails

I'm trying to render a the index view inside my ruby-on-rails application. How do a I render the index view, from inside a view passing an array of things to display? Using the link_to.
I do not want to re-route to the controller, I just want to link_to a view passing it the variables it needs, how can I do this?
EDIT:
I am trying to create a page type functionality in the index of my article model. So I have around 400 articles for example, and when the index action in the article controller is called, it of course renders the index view which is calling a partial for each article in the '#articles array' passed on by article controller's index action.
So in the view, I'm trying to do something like:
<% count = 0 %>
<% #articles.each do |article| %>
<% if count <10 %>
<%= render partial: 'index_articles', locals: {article: article} %>
<% count = count + 1 %>
<% end %>
<% end %>
<% #articles = #articles.drop(10) %>
<% if #articles.any? %>
<%= link_to "Next", 'articles', locals: {#articles => #articles} %>
<% end %>
Thank you in advanced for all of your help.
You'll need to use the render command, probably with a partial:
<%= render "controller/index", collection: ["your", "array"], as: :object_name %>
You will have to call a controller action to generate this. You cannot simply load it on your screen, unless it was preloaded inside your javascript for something:
#View
<%= link_to "Index", controllers_path(ids: ["1","2"]), remote: true %>
#app/controllers/your_controller.rb
class YourController < ApplicationController
def index
#posts = request.xhr? Post.find(params[:ids]) : Post.all
respond_to do |format|
format.js #-> app/views/controller/index.js.erb
format.html
end
end
end
#app/views/controller/index.js.erb
$(".element").html("<%=j render 'index' %>");
There are several issues with this approach...
Flow
First of all, your flow of your app should be as structured as possible.
In short, if you're calling the index view inside another action, it's not the index view any more.
What you should look at is how to use a partial in your app:
#app/controller/views/_partial.html.erb
<%= post.title %>
This way, you can adapt your index view and your other page to use the partial in their respective action layouts:
#app/controller/views/index.html.erb
<%= render "partial", collection: #posts, as: :post %>
This will allow you to "reuse" code much in the way you want. This will be much more appropriate than trying to invoke other action/views.
-
Resources
Secondly, you'll want to look at how your app functions.
Your index view is meant to show all the items for a particular object. Whilst you're free to change this as you want, the fact remains that you have to keep some structure.
You should read up on the routes for your actions, and how they're meant to work in your application. This will give you some perspective on the resourceful nature of Rails routes, and how you'll have to call specific routes with specific actions.
Your problem is probably that the file needs to be named _index.html.erb. You can have another file named index.html.erb which just renders _index.html.erb.
If you need a full guide on using AJAX, look up the railscast. If you're not using AJAX and you just want to render it, then you don't use link_to. You just do <%= render :index %>.

Deleting records using forms in rails 3.2

I have two models, users and materials. Users can favourite materials. I have set up the relationships and the code for favouriting works fine but I can't seem to get the code for unfavouriting right. I have the following code for unfavouriting:
Materials Controller (in show action where unfavourite form is)
#favourite = Favmat.where(:user_id => current_user.id, :material_id => #material.id)
Note: I use this code to decide which button to show in the view. Assuming a record exists we get this:
View
<%= form_for #favourite, :method => :delete do |f| %>
<%= f.submit "Unfavourite" %>
<% end %>
The problem seems to be here. Nothing I do seems to get me a working route to the destroy action in the favmats controller. I have tried using a form_tag instead but then I get very odd routes that don't work.
Favmats Controller
def destroy
Favmat.find(params[:id]).destroy
respond_to do |format|
format.html { redirect_to #material }
format.js
end
end
Update
I have also tried using link_to instead of a form. The code is as follows:
<%= link_to "Unfavourite", favmat_path, method: "delete" %>
The weird thing is that the html for this takes the favmat id from the material, not the favmat object. I don't know how to get the favmat object id in there. Nothing seems to work.
Try passing #favourite object instead of favmat_path to link_to:
<%= link_to "Unfavourite", #favourite, method: :delete %>

How do I use another value of a key in a hash if the first one doesn't exist, like some type of fallback in ruby/rails?

Basically I have a follow button and when click the page refreshes and I show an unfollow button in place. Below is the code I use to render the particular form needed:
follow_forms partial:
<% unless current_user?(#user) %>
<% if current_user.following?(#user) %>
<%= render 'relationships/partials/unfollow' %>
<% else %>
<%= render 'relationships/partials/follow' %>
<% end %>
<% end %>
Any I changed the form to an ajax form because I don't want the page refresh and on success of the form submission I'd like to replace the follow button/form with an unfollow button/form. This isn't straight forward because only 1 form shows at a time so I can't use my jquery selector to find this form anyway.
What I decided to do was create a new action that renders the follow_form partial this way the appropriate form will be available for me to manipulate with my jquery selector.
The new action:
class RelationshipsController < ApplicationController
def get_follow_form
respond_to do |format|
format.html { render :partial => 'relationships/partials/follow_form_ajax' }
end
end
end
The problem now is that I don't have access to the #user instance variable. That doesn't matter to much because I can get the user who was just followed via the jquery success data then pass that as data in the new ajax call to get_follow_form_url and then pass that info into the partial as a local variable.
I still have an issue with the #user instance variable not being available. Which brings me to my question.
How can I make another value be used if the instance variable isn't nil/doesn't exist?
The form for following:
<%= form_for current_user.relationships.build(:followed_id => #user.id), :remote => true do |f| %>
<%= f.hidden_field :followed_id %>
<%= f.submit "Follow", :class => 'followButton' %>
<% end %>
Can I do something like this
:followed_id => #user.id <-if this doesn't exist use this-> user.id
There are other ways around this like creating new partials that are only used for this whole situation or creating some messy if statements but I feel like creating duplicate forms should be my very very very last option.
I look forward to you solutions thanks
Kind regards
There's a very simple way to do this, assuming you have your 'fallback' ID:
:followed_id => #user.present? ? #user.id : fallback_id
Use something like the andand gem or just try and a logic expression:
:followed_id => #user.andand.id || user.id
Even without that you can use identical logic, and certainly don't need multiple partials:
:followed_id => (#user && #user.id) || user.id
But as Frederick says, if you have a replacement value for the object already, couldn't you just set it?

Resources