So I'm using has_and_belong_to_many association for two models (Article and Category). My header have link with dropdown menu where different categories appears. All my articles are on index page and I need to sort it depending what category it has so users could choose what they want to see. I guess I should do something in show action in category controller, but don't know what exactly. To solve this I played with different each iterations in my views and controller, but unfortunately it didn't help.
Any help will be appreciated
You can select articles with certain category with
selected_articles = Category.find_by_name("Name of category").articles
Or, if you don't know the name simply
selected_articles = Category.find(category_id).articles
Article.joins(:category).where(categories: {id: :your_category_id})
#config/routes.rb
resources :articles do
get ":category_id", action: :index, on: :collection #-> url.com/articles/:category_id
end
#app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def index
if params[:category_id]
#articles = Article.joins(:categories).where(category: {id: params[:category_id]})
else
#articles = Article.all
end
end
end
This will allow you to use:
#app/views/articles/index.html.erb
<%= form_tag articles_path do %>
<%= f.collection_select :category_id, Category.all, :id, :name %>
<%= f.submit %>
<% end %>
<% #articles.each do |article| %>
<%= article.title %>
<% end %>
Related
I have two models, articles and tags, with a has_and_belongs_to_many relationship. There is a simple join table with two columns, article_id and tag_id, with no index. In my articles index template I want to be able to filter on specific tags using a select box where you select the tag.name field and this is put in the url as a query sting and the controller filters the articles by that tag. Below is my setup and it throws the error "SQLite3::SQLException: no such column: articles.tag_id". It is correctly adding ?tag=name to the url and the controller is correctly assigning #tag but it fails from there. How do I get this to work?
Models
# app/models/article.rb
has_and_belongs_to_many :tags
#app/models/tag.rb
has_and_belongs_to_many :articles
Controller
# app/controllers/articles_controller.rb
def index
if params[:tag]
#tag = Tag.find_by(name: params[:tag])
#articles = Article.where(tag_id: #tag.id)
else
#articles = Article.all
end
end
View
# app/views/articles/index.html.erb
<%= form_tag(articles_path, method: "get") do %>
<%= select_tag "tag", options_from_collection_for_select(Tag.all, "name"),
prompt: "Select Tag" %>
<%= submit_tag "Submit" %>
<% end %>
# app/views/articles/index.html.erb
<%= form_tag(articles_path, method: "get") do %>
<%= select_tag "tag_ids", options_from_collection_for_select(Tag.all, :id, :name),
prompt: "Select Tag", multiple: true %>
<%= submit_tag "Submit" %>
<% end %>
# app/controllers/articles_controller.rb
def index
if params[:tag_ids]
#articles = Article.joins(:tags).where('tags.id' => params[:tag_ids])
else
#articles = Article.all
end
end
See Active Record Query Interface - Specifying Conditions on the Joined Tables
I want to get data from multiple table in rails,but it is not working.
Here is my code.
Category.rb
has_many :posts
post.rb
has_many :mini_posts
belongs_to :category
mini_post.rb
belongs_to :post
controller
#posts = Category.find(params[:id]).posts.mini_posts
viewfile
<% #posts.each do |post| %>
<%= post.title %>
<%= post.description %>
<% post.mini_posts.each do |mpost| %>
<%= mpost.name %>
<%= mpost.experience %>
<% end %>
<% end %>
The error shows "undefined method `mini_posts'.
How can I solve this?
Your code is chaining methods, and returning mini posts, not eager loading the mini posts which is what I assume you want.
You want either
#posts = Post.includes(:mini_posts).where(category_id: params[:id])
Or
#category = Category.includes(posts: :mini_posts).find(params[:id])
#posts = #category.posts
Change
#posts = Category.find(params[:id]).posts.mini_posts
to
#posts = Category.find(params[:id]).posts
Two of the models I have in the rails 4 app are the following:
class Council < ActiveRecord::Base
has_many :alternatives
...
end
class Alternative < ActiveRecord::Base
belongs_to :council
...
end
I am rendering an Alternative form that allows me to create a new Alternative object from a Council's show view:
councils/show.html.erb
<%= render 'alternatives/form' %>
alternatives/_form.html.erb
<%= form_for(#alternative) do |f| %>
<div class="form-group">
<div>
<%= f.text_field :title, :placeholder => 'Provide your alternative', autofocus: true, class:"form-control" %>
</div>
<div>
<%= f.text_area :more_info, :placeholder => 'Describe your alternative', autofocus: true, class:"form-control", rows: '4' %>
</div>
</div>
<div>
<%= f.submit 'Submit the alternative!', class:"btn btn-success" %>
</div>
<% end %>
At that point, I want to associate the Alternative object with the specific Council object from the show view, like the code below, but the variable #council is not defined:
controllers/alternatives_controller.rb
class AlternativesController < ApplicationController
before_action :set_alternative, only: [:show, :edit, :update, :destroy]
def create
#alternative = Alternative.new(alternative_params)
#alternative.council = #council
end
private
def set_alternative
#alternative = Alternative.find(params[:id])
end
def alternative_params
params.require(:alternative).permit(:title, :more_info)
end
end
That will allow me to show all the alternatives associated with a certain Council object:
councils/show.html.erb
...
<% #council.alternatives.each do |alternative| %>
<%= alternative.title %>
<%= alternative.more_info %>
<% end %>
...
I've carefully reviewed the Ruby on Rails Guides (http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference) but clearly I am missing something. Any ideas? Thank you.
Several options for you:
Nested
I've not tested this, but you could use multiple objects in your form_for helper:
#app/views/councils/show.html.erb
<%= form_for [#council, #alternative] do |f| %>
...
<% end %>
This will send your request through to the council_alternatives_path (you can change it), and provide you with params[:council_id] and params[:id]
You could set your routes like this to get it to work:
#config/routes.rb
resources :councils do
resources :alternatives, only: [:create]
end
This will be a little hacky I think (as it's meant for forms with nested attributes), but it's still a viable way to achieve what you want
Nested Attributes
The other option is to use the accepts_nested_attributes_for directive in your model. This will be overkill for what you need I think, but could help:
#app/models/council.rb
Class Council < ActiveRecord::Base
has_many :alternatives
accepts_nested_attributes_for :alternatives
end
#app/models/alternative.rb
Class Alternative < ActiveRecord::Base
belongs_to :council
end
This will allow you to use the #council object to save any new Alternative objects you need:
#app/controllers/councils_controller.rb
Class CouncilsController < ApplicationController
def show
#council = Council.find params[:id]
#council.alternatives.build
end
def update
#council = Council.find params[:id]
#council.update(council_params)
end
private
def council_params
params.require(:council).permit(alterantives_attributes: [:alternatives, :attributes])
end
end
This will allow you to use the following form code:
#app/views/councils/show.html.erb
<%= form_for #council do |f| %>
<%= f.fields_for :alternatives do |a| %>
<%= a.text_field :your_info %>
<% end %>
<% f.submit %>
<% end %>
What do your routes.rb look like? In this case, it seems like the easiest thing would be to have your alternative nested under your council routes, so something like this:
resources :councils do
resources :alternatives
end
In which case, in your alternatives_controller.rb in the create action, you have to just set the #council object from the parameters.
ie.
def create
#council = Council.find(params[:council_id])
#alternative = Alternative.new(alternative_params)
#alternative.council = #council
#alternative.save
end
Personally I would nest it in the routes as derekyau stated above (https://stackoverflow.com/a/25109545/3105349)
But you could also use a hidden field in the form to pass through the council id i.e.
<%= hidden_field :council_id, #council.id %>
Then in the controller you can access it through the params
#council = Council.find(params[:alternative][:council_id])
or add it to your alternative params to assign it automatically
def alternative_params
params.require(:alternative).permit(:title, :more_info, :council_id)
end
But again, making it a nested route is the cleaner and preferred solution.
Friends I just want to show a single post against its description.
On my home page I have all the descriptions and when a user clicks any description then user should be redirected to its respective post.
I have two models one for Post and Descrip.
Descrip belongs_to Post
and
Post has_one Descrip
I just want to know that if user clicks on any description then on next page a post should appear related to that description.
Kindly help or suggest me how i can do that. At this time I just get all the posts when user click a description link. Any help will be highly appreciated. I have partial file which i render to my home page.This partila file have a link button as below
<% #post.reverse_each do |post| %>
<li>
<p>
<%= descrip.description %>
</p>
<%=link_to 'APPLY TO THIS JOB', descriptions_view_path, :class => 'read_more pull_rigt' %>
<% end %>
View.html.erb where i render my partial file look like this
<%= render partial: 'posts/post', locals: { post: Post.all} %>
and posts controller have two methods
def show
redirect_to post_path(Post.all) and return
end
def index
#posts = Post.all(:order => "created_at DESC")
end
and description controller have a view method
def view
#descrip = Descrip.find_by_id(params[:post_id])
#post = Post.all
end
Do this:
#config/routes.rb
root to: "descriptions#index"
resources :descriptions
#app/controllers/descriptions_controller.rb
def index
#descriptions = Description.all
end
def show
#description = Description.find params[:id]
end
#app/models/description.rb
Class Description < ActiveRecord::Base
has_one :post
end
#app/views/descriptions/index.html.erb
<% for description in #descriptions do %>
<%= link_to description.title, description_path(description.id) %>
<% end %>
#app/views/descriptions/show.html.erb
<%= #description.post %>
My form
<% form_for #search do |f| %>
<%= f.input :name_like_any %>
...
<% end %>
Controller
#search = Product.search
#search.name_like_any(params[:search][:name_like_any].split(/\s+/))
#products = search.all
This returns the correct result, but now my form shows the name as ["foo", "bar"] instead of what the user input ("foo bar").
What's the elegant way to handle this?
Appreciate any feedback
Solution
Well, I found out the hard way first, then by asking another question, I inadvertently found a better answer to my original question. Here's the secondary question.
Model
# app/models/product.rb
class Product < ActiveRecord::Base
scope_procedure :keywords, lambda { |query|
name_like_any(query.split(/\s+/))
}
end
Controller
# app/controllers/products_controller.rb
class ProductsController < ApplicationController
def index
#search = Product.search(params[:search])
#products = #search.all
end
end
Views
# app/views/products/index.html.erb
<% form_for #search do |f| %>
<%= f.label :keywords, "Quick Search" %>
<%= f.input :keywords %>
<%= f.submit, "Go" %>
<% end %>
Stay tuned...
I'm having difficulty rallying up some of the more hard-to-answer questions for Searchlogic 2.x, but because tasks aren't always so straightforward, other questions tend to surface. Here's one I hope to answer that's not covered here.
How to sanitize form params for use with Searchlogic?