How to output a specific category in my view? - ruby

i have a rails 3 blog application which has article and category "category belongs_to :article" Article has_many :category, now I have different category which have many article for instance sport category which contain all sport article, what i want in my application layout i want to show only sport article in on div please tell me how to go about it. thank you ...
class Article < ActiveRecord::Base
attr_accessible :category_id, :content, :excerpt, :title, :image, :remote_image_url
mount_uploader :image, ImageUploader
belongs_to :category
validates :title, :content, :excerpt, :category_id, presence: true
validates :title, uniqueness: true
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
def long_title
" #{title} - #{created_at} "
end
end

Updated according to your comments:
First step, get all the categories, let's say you do this in categories#index action:
def index
#categories = Category.all
end
Now we're going to make a link to each category with that category's name in the categories#index view. When users click on a category they will be taken to that category's show page where we'll list all related articles:
<% #categories.each do |category| %>
<%= link_to category.name, category %>
<% end %>
We add the following in the categories#show action:
def show
#category = Category.includes(:articles).find(params[:id])
#articles = #category.articles
end
Then you can show all those articles by iterating over the #articles variable in the corresponding categories#show view. For example adding them as links in a some div:
<div class="articles">
<% #articles.each do |article| %>
<%= link_to article.title, article %><br>
<% end %>
</div>
Now do the same in the articles controller for the show action:
def show
#article = Article.find(params[:id])
end
So basically a user will see a link that says "Sports", when he clicks on it he will be taken to a page such as yoursite.com/categories/4 or yoursite.com/categories/sports if you're using friendly_id. Under this page all related sports articles will be listed and when they are clicked on the user will be taken to that article's show page.

Related

Saving associated many to many relation in Rails

I looked at related posts but could not get my code working. I have device and project models which are connected thru projects_devices table. My models look like this:
class Device < ActiveRecord::Base
has_many :projects, :through => :projects_devices
has_many :projects_devices
accepts_nested_attributes_for :projects_devices, allow_destroy: true
end
class Project < ActiveRecord::Base
has_many :devices, :through => :projects_devices
has_many :projects_devices
accepts_nested_attributes_for :projects_devices
end
class ProjectsDevice < ActiveRecord::Base
belongs_to :device
belongs_to :project
end
my device controller:
def new
#device = Device.new
project_device = #device.projects_devices.build
#projects = Project.all
end
def create
#device = Device.create(device_params)
end
and my device_param :
def device_params
params.require(:device).permit(:name, :projects_devices_attributes => [:id , project_id: []])
end
My view:
<%= f.label :Projects_devices %><br>
<%= f.fields_for :projects_devices do |proj| %>
<%= proj.select(:project_id, [], {}, {class: "form-control projects-devices", multiple: "multiple" } ) do %>
<% if (#projects) %>
<% for #project in #projects %>
<%= content_tag(:option, #project.name, value: #project.id) %>
<% end %>
<% end %>
<% end %>
<% end %>
I have a many to many association between two models. While creating and editing devices, I should be able to list all the projects available. And select only the ones required. When I save, the projects_devices table should be updated.
I have multiple problems here:
When I save a new device,
a. the projects_devices table has only device_id but not project_id. project_id is null
b. if there are 2 projects and I select only one, even then, two association records are created with only device_id (as mentioned above, project_id is missing). It should create only one association.
When a new device is edited,
a. Project list, list of all projects is empty.
b. I see 2 select boxes are displayed instead of one for projects(there are 2 projects currently).
c. updating the device is not happening.
I checked the params:
"device"=>{"name"=>"ABC",
"projects_devices_attributes"=>{"0"=>{"project_id"=>["",
"298486374"]}}},
"commit"=>"Create Device"}
My rails log shows that my application is inserting only device_id:
SQL (0.1ms) INSERT INTO `projects_devices` (`device_id`) VALUES (980190994)
Can somebody help me figure out the problem
Im not sure, but try this params.
Maybe it helps. :)
def device_params
params.require(:device).permit(:name, :projects_devices_attributes =>[:id, :device_id, :project_id, :_destroy])
end

Skip has_many :through Model Creation on No Change

This could be the wrong way to go about this entirely, and I'm very open to alternatives.
I've got the following models, where Users can have many Positions:
class User < ApplicationRecord
has_many :user_positions
has_many :positions, through: :user_positions
accepts_nested_attributes_for :user_positions,
reject_if: :all_blank
end
class UserPosition < ApplicationRecord
belongs_to :user
belongs_to :position
end
class Position < ApplicationRecord
end
On my edit user form, I'd like to allow a User's current position to be updated. I do that in the following way:
<%= form_for #user do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :user_positions, #user.user_positions.order(created_at: :desc).first do |ff| %>
<%= ff.hidden_field :user_id, value: #user.id %>
<%= ff.collection_select :position_id, Position.all, :id, :label %>
<% end %>
<%= f.submit "Update User" %>
<% end %>
The issue I'm running into is that a new instance of UserPosition is being created every time I submit the form, even if the Position that's selected hasn't changed. This leads to a bunch of duplicate entries in the join table, when I really only care about "promotions" or "demotions" when the value of position_id has changed.
I don't want to add a custom validator to disallow the creation, because I still want the form to be able to submit with an unchanged position. An example of this is when I only want to change the User's name.
Any advice on how to deal with this use case?
It turns out that you can actually use any method as a Symbol argument the to accepts_nested_attributes_for reject_if option.
I updated my User model as follows, and now the behavior is exactly what I want:
class User < ApplicationRecord
has_many :user_positions
has_many :positions, through: :user_positions
accepts_nested_attributes_for :user_positions,
reject_if: :same_as_previous_position
def same_as_previous_position(attributes)
if self.user_positions.empty?
return false
end
Position.find(attributes[:position_id]) == self.user_positions.order(created_at: :desc).first.position
end
end

Rails Validation of Association IDs

I am building a Rails 4.2.4 app where I have Units and Medics. When I edit each unit I have two spots for the medics, incharge and attendant. I want some way to validate that both the incharge_id and attendant_id are not the same. That way I can't assign myself as both positions on the unit.
Here is what my model and form view looks like.
unit.rb
class Unit < ActiveRecord::Base
belongs_to :attendant, :foreign_key => :attendant_id, :class_name => 'Medic'
belongs_to :incharge, :foreign_key => :incharge_id, :class_name => 'Medic'
belongs_to :unit_status
end
medic.rb
class Medic < ActiveRecord::Base
has_many :units
end
units/_form.html.erb
<%= form_for(#unit) do |f| %>
<%= f.label 'Attendant'%>
<%= f.collection_select(:attendant_id, Medic.order('name ASC'), :id, :name, {}) %>
<%= f.label 'In Charge'%>
<%= f.collection_select(:incharge_id, Medic.order('name ASC'), :id, :name, {}) %>
<%= f.label 'Unit Status'%>
<%= f.collection_select(:unit_status_id, UnitStatus.order("status ASC"), :id, :status, {})%>
<%= f.submit "Update" %>
<% end %>
So in summary if I edit a unit and I accidentally assign the id of "1" to the unit, I want to error out and give some sort of message, "Cannot assign the same medic to both positions". Something like that.
The only thing I can think of, is to somehow filter the params in the controller saying if the params of attendant_id and incharge_id are are == then redirect to the edit_unit_path and display a flash message, "You cannot assign the same medic to both positions".
It seems like it would be better to do validations on the model side instead of stuffing logic in the controller, but I'm not sure how to simultaneous validate the two different columns for uniqueness.
I came up with this on the Unit model.
validate :attendant_and_incharge
def attendant_and_incharge
errors.add(:attendant_id, "can't be the same as the incharge") if attendant_id == incharge_id
end
This will not allow me to save the same id to the unit model for attendant_id and incharge_id. It fails silently and directs to the units_path. Just need to put some conditional in the controller to redirect to the edit path on failure. (ThumbsUp)

Rails 3 creates duplicate form object for nested records when updating them

There are two models
class Category < ActiveRecord::Base
has_many :products
accepts_nested_attributes_for :products, allow_destroy: true
validates_associated :products
end
class Product < ActiveRecord::Base
belongs_to :category
validate_uniqueness_of :name, scope: :category_id
end
And a form for category
<%= simple_form_for #category do |f| %>
<%= f.simple_fields_for :products do |p| %>
<%= render :partial => "product_fields", :locals => { :f => p } %>
<% end %>
<% end %>
As you can see there is a uniqueness validation which makes sure that products are uniq within category. The problem starts when validation is not passed.
Calling #category.update_attributes(params[:category]) results in duplicate form object. When rendering the form with errors rails creates additional associated product with the id of duplicate record but different name.
For example:
Given we have two products within category: Bread and Butter. If set Butter to Bread when editing a category's products a new form object will be created and the form will be rendered with Bread, Butter, Bread, saying last entry has a duplicate name.
How can i prevent rails from creating those duplicate records? I'm using rails 3.2.11 if it matters.

Edit a Parent Class from a Child Form

Currently, I am able to create multiple Students through my Adult Form by using accepts_nested_attributes_for :student.
But how can I Edit an existing Adult through a Student Form? (So the Opposite, except Edit)
Currently I am able to create more Parents through my Student form, but thats not what I want.
MODELS
class Adult < ActiveRecord::Base
has_many :students
accepts_nested_attributes_for :student
end
class Student < ActiveRecord::Base
belongs_to :adult
accepts_nested_attributes_for :adult
end
CONTROLLER
class StudentsController < ApplicationController
def update
#adult = Adult.find(params[:adult_id])
#student = Student.find(params[:id])
if #student.update_attributes(student_params)
redirect_to path
end
end
private
def student_params
params.require(:student).permit(:adult_id, :school_id, :username, :password,
:firstName, :middleName, :lastName, :alias,
adult_attributes: [:id, :name])
end
end
VIEWS
###HOW CAN I UPDATE THE EXISTING PARENT AS OPPOSE TO CREATING ONE
<%= simple_form_for #student.build_adult do |f| %>
<h4>Update Parent Information</h4>
<%= f.label :firstName, 'First Name' %>
<%= f.text_field :firstName, placeholder: "Parent's First Name", :class => "form-control"%>
<%= f.submit "Save & Continue", class: "btn btn-primary"%>
<% end %>
ROUTES
resources :adult do
resources :student
end
Firstly,it is has_many :students,so it should be accepts_nested_attributes_for :students not accepts_nested_attributes_for :student.
Secondly,if i understood your question correctly,you are trying to update the existing parent(adult) record but you are ending up creating a new one.Is that the problem? If so,you need to permit the :id of the student for which the parent(adult) record need to be updated.
Change your student_params method to like this
def student_params
params.require(:student).permit(:id,:adult_id, :school_id, :username, :password,
:firstName, :middleName, :lastName,:alias,adult_attributes: [:id, :name])
end
I'm not sure about this solution, but it may work...
Try using #parent.update_attributes instead of creating a separate parent form, send the parent params with the student params. You may need to define a parent_params() function to permit them.
** I believe the permit params will filter out the non-permitted ones, so you won't need to specify only the student or parents fields for their respect update_attributes.

Resources