Why i am getting a 422 - Unprocessable Entity Error - ruby-on-rails

I am working on a pinterest clone and I am having some trouble when i try to create a new pin. I get Completed 422 Unprocessable Entity in 3ms (Views: 0.1ms | ActiveRecord: 0.3ms)
I am not sure what else to try. AT first i thought it was my authenticity token and i tried protect_from_forgery unless: -> { request.format.json? } but still doesn't work.
Any suggestions???
routes.rb
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: 'static_pages#root'
namespace :api, defaults: { format: :json } do
resources :users, only: [:show,:new, :create, :index]
resource :session, only: [:new, :create, :destroy, :show]
resources :pins, only: [:create, :show, :index, :edit, :destroy]
resources :boards, only: [:create, :show, :edit, :destroy]
end
end
user.rb
class User < ApplicationRecord
attr_reader :password
validates :username, presence: true, uniqueness: true
validates :password_digest, :session_token, presence: true
validates :password, length: { minimum: 6 }, allow_nil: true
after_initialize :ensure_session_token
has_many :pins,
foreign_key: :author_id,
class_name: :Pin
has_many :boards,
foreign_key: :author_id,
class_name: :Board
has_many :pins_in_boards,
through: :boards,
source: :boards_pins
def self.find_by_credentials(username, password)
user = User.find_by(username: username)
return nil unless user
user.is_password?(password) ? user : nil
end
def password=(password)
#password = password
self.password_digest = BCrypt::Password.create(password)
end
def is_password?(password)
BCrypt::Password.new(self.password_digest).is_password?(password)
end
def ensure_session_token
self.session_token ||= SecureRandom.urlsafe_base64
end
def reset_session_token!
self.session_token = SecureRandom.urlsafe_base64
self.save
self.session_token
end
end
users_controller.rb
class Api::UsersController < ApplicationController
def show
#user = User.find_by(username: params[:id])
if #user
render :show
else
render json: #user.errors.full_messages, status: 404
end
end
def new
#user = User.new
render :new
end
def index
#users =User.all
render :index
end
def create
#user = User.new(user_params)
if #user.save
sign_in(#user)
render "api/users/show"
else
render json: #user.errors.full_messages, status: 422
end
end
private
def user_params
params.require(:user).permit(:password, :username)
end
end
pins_controller.rb
class Api::PinsController < ApplicationController
def index
#pins = user.pins
end
def new
#pin = Pin.new(user_id: current_user.id)
render :new
end
def show
#pin = Pin.find(params[:id])
render :show
end
def create
#pin = current_user.pins.new(pin_params)
if #pin.save
render :show
else
render json: #pin.errors.full_messages, status: 422
end
end
def edit
#pin = Pin.find(params[:id])
unless #pin.author_id == current_user.id
render "api/pins/show"
else
render :edit
end
end
def destroy
pin = current_user.pins.find(params[:id])
pin.destroy
end
private
def pin_params
params.require(:pin).permit(
:title,
:description,
:url,
:author_id,
:photo
)
end
def user
#user ||= User.find(params[:user_id])
end
def pin
#pin ||= current_user.pins.find(params[:id])
end
end
pin.rb
class Pin < ApplicationRecord
validates :title, :description, :author_id, presence: true
belongs_to :user
belongs_to :board
has_many :boards
has_one_attached :photo
has_many :users,
through: :boards,
source: :author
end
creat_pin_form_container.jsx
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import PinForm from './pin_form';
import { createPin } from '../../actions/pins_actions';
import { openModalForm, closeModalForm } from '../../actions/modal_form_actions';
const mapStateToProps = state => ({
pin: {
title: '',
description: '',
photoFile: null
},
formType: 'New Pin'
});
const mapDispatchToProps = dispatch => ({
action: pin => dispatch(createPin(pin)),
closeModalForm: () => dispatch(closeModalForm())
});
export default connect(mapStateToProps, mapDispatchToProps)(PinForm);
pin_form.jsx
import React from 'react';
class PinForm extends React.Component {
constructor(props) {
super(props);
this.state = this.props.pin;
this.handleSubmit = this.handleSubmit.bind(this);
this.handleFile = this.handleFile.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const formData = new FormData();
formData.append('pin[title]', this.state.title);
formData.append('pin[description]', this.state.description);
formData.append('pin[url]', this.state.url);
formData.append('pin[photo]', this.state.photoFile);
this.props.action(formData, this.state.id);
}
update(field) {
return e => this.setState({ [field]: e.currentTarget.value });
}
handleFile(e){
this.setState({ photoFile: e.currentTarget.files[0] })
}
render() {
return (
<div className="pin-form-container">
<form onSubmit={this.handleSubmit}>
<div className="create-edit-form-top">
<nav className="pin-form-header">
<div onClick={this.props.closeModalForm} className="close-pin"><img src={window.cancelURL} /></div>
</nav>
</div>
<div className="new-pin"> <h3>{this.props.formType}</h3></div>
<div className="create-edit-form-left">
<label className="photo-upload">
<img src={this.state.photoUrl} />
<input
type="file"
onChange={this.handleFile}
/>
</label>
</div>
<div className="create-edit-form-right">
<label className="create-edit-form-title">
<input
type='text'
value={this.state.title}
placeholder="Add your title"
onChange={this.update('title')}
/>
</label>
<label className="create-edit-form-description">
<textarea
cols="30"
rows="1"
value={this.state.description}
placeholder="Tell everyone what your Pin is about"
onChange={this.update('description')}
/>
</label>
<label className="add-url">
<input
type='text'
placeholder="Add a destination link"
onChange={this.update('url')}
/>
</label>
</div>
<button className="pin-submit" type='submit'>Save</button>
</form>
</div>
);
}
}
export default PinForm;

Use
protect_from_forgery with: :null_session

Related

NoMethodError- Cant figure out

I am working on a pinterest clone and I am having some trouble when i try to create a new pin. I get "NoMethodError - undefined method pins' for nil:NilClass: app/controllers/api/pins_controller.rb:19:in create'"
I am not sure what else to try. I dont know why it doesnt have access to pins. Any suggestions???
routes.rb
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: 'static_pages#root'
namespace :api, defaults: { format: :json } do
resources :users, only: [:show,:new, :create, :index]
resource :session, only: [:new, :create, :destroy, :show]
resources :pins, only: [:create, :show, :index, :edit, :destroy]
resources :boards, only: [:create, :show, :edit, :destroy]
end
end
user.rb
class User < ApplicationRecord
attr_reader :password
validates :username, presence: true, uniqueness: true
validates :password_digest, :session_token, presence: true
validates :password, length: { minimum: 6 }, allow_nil: true
after_initialize :ensure_session_token
has_many :pins,
foreign_key: :author_id,
class_name: :Pin
has_many :boards,
foreign_key: :author_id,
class_name: :Board
has_many :pins_in_boards,
through: :boards,
source: :boards_pins
def self.find_by_credentials(username, password)
user = User.find_by(username: username)
return nil unless user
user.is_password?(password) ? user : nil
end
def password=(password)
#password = password
self.password_digest = BCrypt::Password.create(password)
end
def is_password?(password)
BCrypt::Password.new(self.password_digest).is_password?(password)
end
def ensure_session_token
self.session_token ||= SecureRandom.urlsafe_base64
end
def reset_session_token!
self.session_token = SecureRandom.urlsafe_base64
self.save
self.session_token
end
end
users_controller.rb
class Api::UsersController < ApplicationController
def show
#user = User.find_by(username: params[:id])
if #user
render :show
else
render json: #user.errors.full_messages, status: 404
end
end
def new
#user = User.new
render :new
end
def index
#users =User.all
render :index
end
def create
#user = User.new(user_params)
if #user.save
sign_in(#user)
render "api/users/show"
else
render json: #user.errors.full_messages, status: 422
end
end
private
def user_params
params.require(:user).permit(:password, :username)
end
end
pins_controller.rb
class Api::PinsController < ApplicationController
def index
#pins = user.pins
end
def new
#pin = Pin.new(user_id: current_user.id)
render :new
end
def show
#pin = Pin.find(params[:id])
render :show
end
def create
#pin = current_user.pins.new(pin_params)
if #pin.save
render :show
else
render json: #pin.errors.full_messages, status: 422
end
end
def edit
#pin = Pin.find(params[:id])
unless #pin.author_id == current_user.id
render "api/pins/show"
else
render :edit
end
end
def destroy
pin = current_user.pins.find(params[:id])
pin.destroy
end
private
def pin_params
params.require(:pin).permit(
:title,
:description,
:url,
:author_id,
:photo
)
end
def user
#user ||= User.find(params[:user_id])
end
def pin
#pin ||= current_user.pins.find(params[:id])
end
end
pin.rb
class Pin < ApplicationRecord
validates :title, :description, :author_id, presence: true
belongs_to :user
belongs_to :board
has_many :boards
has_one_attached :photo
has_many :users,
through: :boards,
source: :author
end
creat_pin_form_container.jsx
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import PinForm from './pin_form';
import { createPin } from '../../actions/pins_actions';
import { openModalForm, closeModalForm } from '../../actions/modal_form_actions';
const mapStateToProps = state => ({
pin: {
title: '',
description: '',
photoFile: null
},
formType: 'New Pin'
});
const mapDispatchToProps = dispatch => ({
action: pin => dispatch(createPin(pin)),
closeModalForm: () => dispatch(closeModalForm())
});
export default connect(mapStateToProps, mapDispatchToProps)(PinForm);
pin_form.jsx
import React from 'react';
class PinForm extends React.Component {
constructor(props) {
super(props);
this.state = this.props.pin;
this.handleSubmit = this.handleSubmit.bind(this);
this.handleFile = this.handleFile.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const formData = new FormData();
formData.append('pin[title]', this.state.title);
formData.append('pin[description]', this.state.description);
formData.append('pin[url]', this.state.url);
formData.append('pin[photo]', this.state.photoFile);
this.props.action(formData, this.state.id);
}
update(field) {
return e => this.setState({ [field]: e.currentTarget.value });
}
handleFile(e){
this.setState({ photoFile: e.currentTarget.files[0] })
}
render() {
return (
<div className="pin-form-container">
<form onSubmit={this.handleSubmit}>
This is occurring because the value of current_user is currently set to nil. You need to make sure you have a logged in user.

Rails nested form checkbox field not saving to my database model

I have a model association between two models Listing & Pricing. These are associated through Listing_Pricings model on a many to many basis.
If a listing is created the user can select through a check box field one of three pricing options which I intend to have saved in a seperate model Listing_Pricings. When a user selects the pricing option I can see it in the params hash but it fails to save in my database model.
Help please
My controller
class ListingsController < ApplicationController
protect_from_forgery except: [:upload_photo]
before_action :authenticate_user!, except: [:show]
before_action :set_listing, except: [:new, :create]
before_action :set_step, only: [:update, :edit]
before_action :is_authorised, only: [:edit, :update, :upload_photo, :delete_photo]
before_action :set_category, only: [:new, :edit, :show]
def new
#listing = current_user.listings.new
#listing.listing_pricings
#urgencies = Urgency.all
end
def create
#listing = current_user.listings.new listing_params
#listing.listing_pricings.first.listing_id = current_listing.id
if #listing.save
redirect_to edit_listing_path(#listing), notice: "Save..."
else
redirect_to request.referrer, flash: { error: #listing.errors.full_messages}
end
end
def edit
#urgencies = Urgency.all
#listing = Listing.find(params[:id])
#listing_category = #listing.category
#category_pricings = #listing_category.pricings.all
#listing_price = #listing.listing_pricings
end
def update
#listing = Listing.find(params[:id])
#listing_category = #listing.category
##category_pricings = #listing_category.pricings.all
##category = Category.find(params[:id])
#category_pricings = #listing_category.pricings.paginate(page: params[:page], per_page: 5)
#listing_pricing = #listing.listing_pricings
##listing_price = #listing_pricing.first.pricing
#listing_price = #listing.listing_pricings.build
#urgencies = Urgency.all
if #step == 2 && #listing.listing_pricings.each do |pricing|
if #listing.has_single_pricing && !pricing.bronze?
next;
else
if pricing[:listing_id].blank?
#|| pricing[:description].blank? || pricing[:complete_by_date].blank? || pricing[:price].blank?
return redirect_to request.referrer, flash: {error: "Invalid Pricing"}
end
end
end
end
if #step == 3 && listing_params[:description].blank?
return redirect_to request.referrer, flash: {error: "Description cannot be blank"}
end
if #step == 4 && #listing.photos.blank?
return redirect_to request.referrer, flash: {error: "You don't have any photos"}
end
if #step == 5
#listing_category_pricings.each do |pricing|
if #listing.has_single_pricing || !pricing.bronze? || !pricing.silver? || !pricing.gold? || !pricing.platinum?
next;
else
if pricing[:overview].blank? || pricing[:description].blank? || pricing[:complete_by_date].blank? || pricing[:price].blank?
return redirect_to edit_listing_path(#listing, step: 2), flash: {error: "Invalid pricing"}
end
end
end
if #listing.description.blank?
return redirect_to edit_listing_path(#listing, step: 3), flash: {error: "Description cannot be blank"}
elsif #listing.photos.blank?
return redirect_to edit_listing_path(#listing, step: 4), flash: {error: "You don't have any photos"}
end
end
if #listing.update(listing_params)
flash[:notice] = "Saved..."
else
return redirect_to request.referrer, flash: {error: #listing.errors.full_messages}
end
if #step < 5
redirect_to edit_listing_path(#listing, step: #step + 1)
else
redirect_to users_dashboard_path
end
end
def show
#listing = Listing.find(params[:id])
#listing_category = #listing.category
#listing_category_pricings = #listing_category.pricings.all
#urgencies = Urgency.all
end
def upload_photo
#listing.photos.attach(params[:file])
render json: { success: true}
end
def delete_photo
#image = ActiveStorage::Attachment.find(params[:photo_id])
#image.purge
redirect_to edit_listing_path(#listing, step: 4)
end
def set_pricing_id
Listing.update_all({pricing_id: true}, {id: params[:listing_id]} )
end
private
def set_step
#step = params[:step].to_i > 0 ? params[:step].to_i : 1
if #step > 5
#step = 5
end
end
def set_category
#categories = Category.all
end
def set_listing
#listing = Listing.find(params[:id])
end
def is_authorised
redirect_to root_path, alert: "You do not have permission" unless current_user.id == #listing.user_id
end
def listing_params
params.require(:listing).permit(:title, :video, :description, :active, :category_id, :budget, :urgency_id, :has_single_pricing,:pricing_id)
end
def category_params
params.require(:category).permit(:name)
end
end
Listing.rb
class Listing < ApplicationRecord
belongs_to :user
belongs_to :category
belongs_to :urgency
has_many :listing_pricings, dependent: :destroy
has_many :pricings, through: :listing_pricings
has_many_attached :photos
has_rich_text :description
validates :title, presence: { message: 'cannot be blank' }
#has_many :pricings
#accepts_nested_attributes_for :pricings
#has_many :listing_categories
end
Pricings.rb
class Pricing < ApplicationRecord
belongs_to :category, optional: false
has_many :listing_pricings
has_many :listings, through: :listing_pricings
enum pricing_type: [:bronze, :silver, :gold, :platinum]
end
ListingPricing.rb
class ListingPricing < ApplicationRecord
belongs_to :listing, optional: true, dependent: :destroy
belongs_to :pricing, optional: true, dependent: :destroy
end
My View
<div class="step-content <%= 'is-active' if #step == 2 %>">
<div class="field">
<div class="control">
<div class="tile is-ancestor">
<% #category_pricings.each do |cp| %>
<div class="tile is-parent">
<article class="tile is-child box">
<div class="subtitle"><%= "#{cp.overview}" %></div>
<div class="content"><%= "Deposit payable: £#{cp.price}" %></div>
<div class="content"><%= "Time to complete: #{pluralize(cp.complete_by_date, 'Day')}" %></div>
<tr valign="bottom"><div class="content"><%= "#{cp.description}" %></div></tr>
<tr valign="bottom"><div class="content"><%= "#{cp.id}" %></div></tr>
<%= f.fields_for :listing_pricings do |lp| %>
<%= hidden_field_tag "pricing_id[]", cp.id %>
<div class="form-group">
<%= lp.check_box_tag :pricing_id, cp.id %>
</div>
<% end %>
</article>
</div>
<% end %>
</div>
</div>
</div>
</div>
My error trace says
PG::NotNullViolation: ERROR: null value in column "pricing_id" violates not-null constraint DETAIL: Failing row contains (16, 2, null, 2019-12-13 17:51:50.722906, 2019-12-13 17:51:50.722906).
Any thoughts guys ?
Parameters:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"tOnX6Q5YjHgXn3Xk5Wh2NioPfLrziiPVwyHkLF8BBFOjuWHdM1w8A7AdGpHdFGR3n+zlFsN2B/3IOMenXU1daA==",
"step"=>"2",
"listing"=>{"title"=>"Please clean my home", "category_id"=>"3", "urgency_id"=>"10", "has_single_pricing"=>"0", "description"=>"<div>This is my second listing </div>", "video"=>""},
"pricing_id"=>"1",
"commit"=>"Save & Continue",
"id"=>"2"}
I do this for one of my project. I replace my models with Pricing, Listing and ListPricing for you.
In your model, you have to have dependent: :destroy on has_many ... through relationship (otherwise, unchecking checkbox will not work).
# app/model/listing.rb
class Listing < ApplicationRecord
has_many :listing_pricings
has_many :pricings, through: :listing_pricings, dependent: :destroy
# your code
end
In your view,
- Pricing.all.each do |p|
= f.check_box :pricing_ids, { multiple: true }, p.id, false
= f.label :pricing_id, p.something
end
In listing controller, make sure you permit :pricing_ids in listing controller
# app/controllers/listings_controller.rb
def listing_param
params.require(:listing).permit(
# other params you permit,
pricing_ids: []
)
end

Ruby on Rails: :topic_id=>nil, I'm lost

So I am working on an assignment at the moment, where I am trying to display favorited posts. I currently have the favorited post displayed, but when I click it, it doesn't doesn't redirect me to anywhere.
Here is the code I currently have:
User#show where I am currently trying to display the favorited posts:
<div class="row">
<div class="col-md-8">
<div class="media">
<br />
<% avatar_url = #user.avatar_url(128) %>
<% if avatar_url %>
<div class="media-left">
<%= image_tag avatar_url, class: 'media-object' %>
</div>
<% end %>
<div class="media-body">
<h2 class="media-heading"><%= #user.name %></h2>
<small>
<%= pluralize(#user.posts.count, 'post') %>,
<%= pluralize(#user.comments.count, 'comment') %>
</small>
</div>
</div>
</div>
</div>
<h2>Posts</h2>
<%= posts_exists? %>
<%= render #user.posts %>
<h2>Comments</h2>
<%= comments_exists? %>
<%= render #user.comments %>
<h2>Favorites</h2>
<% #posts.each do |post| %>
<%= render partial: 'votes/voter', locals: { post: post } %>
<%= link_to post.title, topic_post_path(#topic, post) %>
<%= image_tag current_user.avatar_url(48), class: "gravatar" %>
<%= post.comments.count %> Comments
<% end %>
The error is occuring on the following line:
<%= link_to post.title, topic_post_path(#topic, post) %>
Here is the output from the error:
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"posts", :id=>"54", :topic_id=>nil} missing required keys: [:topic_id]):
29: <h2>Favorites</h2>
30: <% #posts.each do |post| %>
31: <%= render partial: 'votes/voter', locals: { post: post } %>
32: <%= link_to post.title, topic_post_path(#topic, post) %>
33: <%= image_tag current_user.avatar_url(48), class: "gravatar" %>
34: <%= post.comments.count %> Comments
35: <% end %>
app/views/users/show.html.erb:32:in `block in _app_views_users_show_html_erb__1919900632491741904_70127642538380'
app/views/users/show.html.erb:30:in `_app_views_users_show_html_erb__1919900632491741904_70127642538380'
Obviously Topid.id is nil, but I can't figure out why. I'm going to provide you with everything I think you could need? I know this is probably a simple nooby issue, but I've been stuck on it for nearly an entire day already.
Here is my User#Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new
#user.name = params[:user][:name]
#user.email = params[:user][:email]
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][:password_confirmation]
if #user.save
flash[:notice] = "Welcome to Bloccit #{#user.name}!"
create_session(#user)
redirect_to root_path
else
flash[:error] = "There was an error creating your account. Please try again."
render :new
end
end
def show
#user = User.find(params[:id])
#posts = #user.posts.visible_to(current_user)
#posts = Post.joins(:favorites).where('favorites.user_id = ?', #user.id)
#favorites = current_user.favorites
end
end
Here is my Post#Controller:
class PostsController < ApplicationController
before_action :require_sign_in, except: :show
before_action :authorize_user, except: [:show, :new, :create]
def show
#post = Post.find(params[:id])
end
def new
#topic = Topic.find(params[:topic_id])
#post = Post.new
end
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.build(post_params)
#post.user = current_user
if #post.save
#post.labels = Label.update_labels(params[:post][:labels])
flash[:notice] = "Post was saved."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :new
end
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
#post.assign_attributes(post_params)
if #post.save
#post.labels = Label.update_labels(params[:post][:labels])
flash[:notice] = "Post was updated."
redirect_to [#post.topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :edit
end
end
def destroy
#post = Post.find(params[:id])
if #post.destroy
flash[:notice] = "\"#{#post.title}\" was deleted successfully."
redirect_to #post.topic
else
flash[:error] = "There was an error deleting the post."
render :show
end
end
private
def post_params
params.require(:post).permit(:title, :body)
end
def authorize_user
post = Post.find(params[:id])
unless current_user == post.user || current_user.admin?
flash[:error] = "You must be an admin to do that."
redirect_to [post.topic, post]
end
end
end
Here is my Topics#Controller:
class TopicsController < ApplicationController
before_action :require_sign_in, except: [:index, :show]
before_action :authorize_user, except: [:index, :show]
def index
#topics = Topic.all
end
def show
#topic = Topic.find(params[:id])
end
def new
#topic = Topic.new
end
def create
#topic = Topic.new(topic_params)
if #topic.save
#topic.labels = Label.update_labels(params[:topic][:labels])
redirect_to #topic, notice: "Topic was saved successfully."
else
flash[:error] = "Error creating topic. Please try again."
render :new
end
end
def edit
#topic = Topic.find(params[:id])
end
def update
#topic = Topic.find(params[:id])
#topic.assign_attributes(topic_params)
if #topic.save
#topic.labels = Label.update_labels(params[:topic][:labels])
flash[:notice] = "Topic was updated."
redirect_to #topic
else
flash[:error] = "Error saving topic. Please try again."
render :edit
end
end
def destroy
#topic = Topic.find(params[:id])
if #topic.destroy
flash[:notice] = "\"#{#topic.name}\" was deleted successfully."
redirect_to action: :index
else
flash[:error] = "There was an error deleting the topic."
render :show
end
end
private
def topic_params
params.require(:topic).permit(:name, :description, :public)
end
def authorize_user
unless current_user.admin?
flash[:error] = "You must be an admin to do that."
redirect_to topics_path
end
end
end
Here is my User Model:
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :votes, dependent: :destroy
has_many :favorites, dependent: :destroy
before_save { self.email = email.downcase }
before_save { self.role ||= :member }
EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, length: { minimum: 1, maximum: 100 }, presence: true
validates :password, presence: true, length: { minimum: 6 }, if: "password_digest.nil?"
validates :password, length: { minimum: 6 }, allow_blank: true
validates :email,
presence: true,
uniqueness: { case_sensitive: false },
length: { minimum: 3, maximum: 100 },
format: { with: EMAIL_REGEX }
has_secure_password
enum role: [:member, :admin]
def favorite_for(post)
favorites.where(post_id: post.id).first
end
def avatar_url(size)
gravatar_id = Digest::MD5::hexdigest(self.email).downcase
"http://gravatar.com/avatar/#{gravatar_id}.png?s=#{size}"
end
end
Here is my Topic Model:
class Topic < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :labelings, as: :labelable
has_many :labels, through: :labelings
end
Here is my Post Model:
class Post < ActiveRecord::Base
belongs_to :topic
belongs_to :user
has_many :comments, dependent: :destroy
has_many :votes, dependent: :destroy
has_many :labelings, as: :labelable
has_many :labels, through: :labelings
has_many :favorites, dependent: :destroy
default_scope { order('rank DESC') }
scope :visible_to, -> (user) { user ? all : joins(:topic).where('topics.public' => true) }
validates :title, length: { minimum: 5 }, presence: true
validates :body, length: { minimum: 20 }, presence: true
validates :topic, presence: true
validates :user, presence: true
def up_votes
votes.where(value: 1).count
end
def down_votes
votes.where(value: -1).count
end
def points
votes.sum(:value)
end
def update_rank
age_in_days = (created_at - Time.new(1970,1,1)) / 1.day.seconds
new_rank = points + age_in_days
update_attribute(:rank, new_rank)
end
end
Any insight anyone could provide, I would be extremely grateful for. If you have the time to explain where I went wrong as well, that would be even more helpful.
User#show where I am currently trying to display the favorited posts
But you're not setting #topic in your User#show action. That's why it's nil.
def show
#user = User.find(params[:id])
#posts = #user.posts.visible_to(current_user)
#posts = Post.joins(:favorites).where('favorites.user_id = ?', #user.id)
#favorites = current_user.favorites
# your #topic object is not in here?
end
Since a post belongs_to a topic you could do something like this:
<%= link_to post.title, topic_post_path(post.topic, post) %>

Multi-select validation always fail

I have few multi-selects in my app that validation always fail (getting form errors: genres can't be blank, languages can't be blank) during every form submit (even if the multi-select options were selected). Code:
models/dvd.rb
class Dvd < ActiveRecord::Base
has_and_belongs_to_many :genres
has_and_belongs_to_many :languages
has_many :rentals, dependent: :destroy
has_many :users, through: :rentals
validates :title, presence: true
validates :year, inclusion: {in: 1900..Time.now.year.to_i}, :presence => {:message => 'Year must be from 1900 till current year.'}
validates :length, inclusion: {in: 1..999}, :presence => {:message => 'DVD length must be in minutes in range 1..999.'}
validates :genres, presence: true
validates :languages, presence: true
end
models/language.rb
class Language < ActiveRecord::Base
has_and_belongs_to_many :dvds
validates :title, presence: true, uniqueness: { case_sensitive: false }
end
models/genre.rb
class Genre < ActiveRecord::Base
has_and_belongs_to_many :dvds
validates :title, presence: true, uniqueness: { case_sensitive: false }
end
dvds_controller.rb
class DvdsController < ApplicationController
before_action :set_dvd, only: [:show, :edit, :update, :destroy]
before_action :set_genres, :set_languages, only: [:new, :edit]
before_action :delete_genres, :delete_languages, only: [:update]
after_action :add_genres, :add_languages, only: [:create, :update]
# GET /dvds
# GET /dvds.json
def index
#dvds = Dvd.all
end
# GET /dvds/1
# GET /dvds/1.json
def show
end
# GET /dvds/new
def new
#dvd = Dvd.new
end
# GET /dvds/1/edit
def edit
end
# POST /dvds
# POST /dvds.json
def create
#dvd = Dvd.new(dvd_params)
respond_to do |format|
if #dvd.save
format.html { redirect_to #dvd, notice: 'Dvd was successfully created.' }
format.json { render :show, status: :created, location: #dvd }
else
format.html { render :new }
format.json { render json: #dvd.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /dvds/1
# PATCH/PUT /dvds/1.json
def update
respond_to do |format|
if #dvd.update(dvd_params)
format.html { redirect_to #dvd, notice: 'Dvd was successfully updated.' }
format.json { render :show, status: :ok, location: #dvd }
else
format.html { render :edit }
format.json { render json: #dvd.errors, status: :unprocessable_entity }
end
end
end
# DELETE /dvds/1
# DELETE /dvds/1.json
def destroy
#dvd.destroy
respond_to do |format|
format.html { redirect_to dvds_url, notice: 'Dvd was successfully deleted.' }
format.json { head :no_content }
end
end
private
def set_dvd
if params[:id]
#dvd = Dvd.find(params[:id])
else
#dvd = Dvd.find(params[:dvd][:id])
end
end
def dvd_params
params.require(:dvd).permit(:title, :description, :year, :genres, :languages, :length)
end
def add_languages
params[:dvd][:languages].each do |l|
if !l.empty?
#dvd.languages << Language.find(l)
end
end
end
def add_genres
params[:dvd][:genres].each do |g|
if !g.empty?
#dvd.genres << Genre.find(g)
end
end
end
def set_genres
#genres = Genre.all
end
def set_languages
#languages = Language.all
end
def delete_genres
# Delete all dvd genre relations
#dvd.genres.delete_all
end
def delete_languages
# Delete all dvd language relations
#dvd.languages.delete_all
end
end
routes.rb
Rails.application.routes.draw do
resources :dvds do
resources :rentals
end
resources :rentals
resources :languages
resources :genres
resources :dvds
resources :users, :path => 'clients'
root to: "index#index"
end
form
<div class="field">
<%= f.label :genres %><br>
<%= f.collection_select(:genres, Genre.all, :id, :title, {:selected => #dvd.genres.map {|dl| dl.id}, :include_blank => false}, {:multiple => true}) %>
</div>
<div class="field">
<%= f.label :languages %><br>
<%= f.select :languages, options_for_select(Language.all.map {|l| [l.title,l.id]}, #dvd.languages.map {|dl| dl.id}), {:include_blank=> false}, {:multiple => true} %>
</div>
Any ideas what is wrong with that?
The field names for the form should be genre_ids and language_ids, not genres and languages.

Ruby on rails trouble with nested form

I have a clan.rb and clan_options.rb
clan.rb
class Clan < ActiveRecord::Base
has_one :options, :class_name => "ClanOptions", :foreign_key => "clan_id", dependent: :destroy
accepts_nested_attributes_for :options
end
clan_options.rb
class ClanOptions < ActiveRecord::Base
belongs_to :clan
end
To create an edit form for clan.rb and clan_options.rb I use the following in edit.html.erb:
<%= form_for #clan, :html => {:class => 'form-horizontal'} do |clan| %>
<fieldset>
<!-- Form stuff -->
<%= clan.fields_for :options do |o| %>
<!-- o.text_field -->
<% end %>
</fieldset>
<% end %>
I can update the fields of clan.rb but when I try to edit the value backgroundurl it won't save it. Backgroundurl is one of the clan_options.rb
clans_controller.rb
class ClansController < ApplicationController
before_filter :check_login, :only => [:new, :edit]
before_filter :check_bound, :only => [:new, :edit]
before_filter :check_clan, :only => :new
def update
#clan = Clan.find(params[:id])
if #clan.update_attributes(clan_update_params)
flash[:status] = TRUE
flash[:alert] = "Successfully updated your clan."
redirect_to clan_path(params[:id])
else
flash[:status] = FALSE
flash[:alert] = #clan.errors.full_messages
redirect_to edit_clan_path(#clan.id)
end
end
def edit
clan = Clan.where(id: params[:id])
if !clan.blank?
#clan = Clan.find(params[:id])
user = User.where(id: session[:user_id])
if !user.blank?
#De gebruiker is ingelogt en zit in de clan
#user = User.find(session[:user_id])
if #clan.id != #user.clan.id
flash[:status] = FALSE
flash[:alert] = 'That was not your clan, you may not edit theirs.'
redirect_to clans_path
elsif #user.clanmember.group.rank != 10
flash[:status] = FALSE
flash[:alert] = "You must be the leader to edit the clan."
redirect_to clan_path(#clan.id)
end
end
else
flash[:status] = FALSE
flash[:alert] = 'that clan doesn\'t exist or has been removed.'
redirect_to clans_path
end
end
def clan_params
params.require(:clan).permit(:name, :prefix, :description, :user_id)
end
def clan_update_params
params.require(:clan).permit(:name, :prefix, :description, :user_id, options: [:id, :clan_id, :backgroundurl])
end
end
I've fixed it by changing
def clan_update_params
params.require(:clan).permit(:name, :prefix, :description, :user_id, options: [:id, :clan_id, :backgroundurl])
end
to
def clan_update_params
params.require(:clan).permit(:name, :prefix, :description, :user_id, options_attributes: [:backgroundurl])
end

Resources