mongoid can't push with HABTM relationship in rails - ruby-on-rails

Im stuck on the issue a few days..Please help, thanks in advance.
This is a rails project on mongoid, there're 2 models in the project, one is User, another CustomSearchEngine:
class User
include Mongoid::Document
# Include default devise modules. Others available are:
......
# keep the CSEs
has_and_belongs_to_many :keeped_custom_search_engines, class_name: 'CustomSearchEngine', inverse_of: :consumers
# create or fork the CSEs
has_many :custom_search_engines, inverse_of: :author, dependent: :destroy
# Index
index({username: 1}, {unique: true, name: 'user_username'})
index({email: 1}, {unique: true, name: 'user_email'})
# Massive assignment for User.new
attr_accessible :email, :username, :agreement, :password, :password_confirmation
attr_accessor :agreement, :password_confirmation
validates :password_confirmation, presence: true
validates :agreement, presence: true
end
class CustomSearchEngine
include Mongoid::Document
include Mongoid::Timestamps
paginates_per 20
...
belongs_to :author, class_name: 'User', inverse_of: :custom_search_engines
has_and_belongs_to_many :consumers, class_name: 'User', inverse_of: :keeped_custom_search_engines
belongs_to :node
# Index
index({author_id: 1}, {name: 'cse_author_id'})
index({node_id: 1}, {name: 'cse_node_id'})
# validations
validates :status, presence: true, inclusion: {in: ['draft', 'publish']}
validates :author_id, presence: true
validates :node_id, presence: true
scope :recent, ->(status) { where(status: status).desc(:created_at) }
...
end
In my CustomSearchEngine controller:
current_user.keeped_custom_search_engines.push(#custom_search_engine)
Then I go to my mongodb, I see only the user document updated:
keeped_custom_search_engine_ids: ["50a208092061c770190000df"]
but the custom search engine document isn't changed:
consumer_ids: []
And I get an error: #messages={:consumers=>["is invalid"]}
Something I missed?

I think this problem is you push consumers before consumer instance save to database.
Try code like this:
def create
#team = Team.new(params[:team])
#team.own = current_user
respond_to do |format|
if #team.save
current_user.push_join_teams(#team.id)
format.html { redirect_to #team, notice: 'Team was successfully created.' }
format.json { render json: #team, status: :created, location: #team }
else
format.html { render action: "new" }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
#user.rb
def push_join_teams(tid)
return false if self.join_team_ids.include?(tid)
self.push(:join_team_ids,tid)
end

Related

Need help validating query parameters

I have multiple methods within my controller that takes in query parameters. How can I validate that I am being passed in valid parameters? For example, for the index method, how can I make sure that I am getting an array of authorIds.
def index
author_ids_array = params[:authorIds].to_s.split(',')
posts = Post
.get_posts_by_user_id(author_ids_array)
.order(sort_column => sort_direction)
if posts
render json: { posts: posts }, status: :ok
else
render json: {error: posts.errors}, status: :unprocessable_entity
end
end
Or in this update method. How can I validate that I am getting a valid postId
def update
post = current_user.posts.find_by(id: params[:id])
if post.update!(post_params)
post_hash = post.as_json
post_hash.merge!(authorIds: params[:authorIds])
render json: {post: post_hash}, status: :ok
else
render json: {error: post.errors}, status: :unprocessable_entity
end
end
Update:
Post Model:
class Post < ApplicationRecord
# Associations
has_many :user_posts
has_many :users, through: :user_posts, dependent: :destroy
# Validations
validates :text, presence: true, length: { minimum: 3 }
validates :popularity, inclusion: { in: 0.0..1.0 }
def tags
if super
super.split(",")
end
end
def tags=(value)
if value.kind_of? Array
super value.join(",")
else
super value
end
end
def self.get_posts_by_user_id(user_id)
Post.joins(:user_posts).where(user_posts: { user_id: user_id })
end
end
User Model:
class User < ApplicationRecord
has_secure_password
# Associations
has_many :user_posts
has_many :posts, through: :user_posts, dependent: :destroy
# Validations
validates :username, :password, presence: true
validates :password, length: { minimum: 6 }
validates :username, uniqueness: true
end
User_post Model:
class UserPost < ApplicationRecord
belongs_to :user
belongs_to :post
end
You can use specific render like below user this in any method like
def index
return render body: params.inspect
.
.
end
user below code
return render body: params.inspect
so when you use index it will give you params which is passing
OR you can user below code in your application.html.erb above <%= yield%>
<%= debug(params) if Rails.env.development? %>
After your clarifications, your question remains unclear to me and it is difficult to guess what you're doing. But I understood that you want to ensure that params[:authorIds] or anything else is an array.
You can see if a given variable is an array the following way:
a = ["1","2"]
if a.is_a?(Array)
puts "is an array"
end
With params: params[:authorIds].is_a?(Array)
You can use byebug (before Rails 7) or debugger (for Rails 7) to inspect what a param is. As an example:
(ruby#whatever: cluster worker 1: 42779 [MyApp]#42793) params[:ids].class
Array

Rails Mongodb can't save record

I'm using Mongodb in my Rails app. I have 2 models, which are Account and User. Account has many users and users belongs to account.
Account model
has_many :users, :inverse_of => :account, :dependent => :destroy
validates :organization_name, presence: true, uniqueness: true
User model
belongs_to :account, :inverse_of => :users
validates :account, :presence => false
validates :email, presence: true
has_secure_password
validates :password, length: { minimum: 6 }, allow_nil: true
def User.new_token
SecureRandom.urlsafe_base64
end
def self.create_with_password(attr={})
generated_password = attr[:email] + User.new_token
self.create!(attr.merge(password: generated_password, password_confirmation: generated_password))
end
User controller
def new
#user = User.find_by(params[:id])
#user = #current_user.account.users.new
end
def create
#user = User.find_by(params[:id])
#user = #current_user.account.users.create_with_password(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
format.js
else
format.html { render 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
format.js { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:id, :email, :password, :password_confirmation, :owner, :admin)
end
I can successfully sign up an account with a user. But when I tried to add a new user, the user record can't be saved. I assigned a password for users when creating a new user.
The error messages:
message: Validation of User failed. summary: The following errors were found: Account can't be blank resolution: Try persisting the document with valid data or remove the validations.
If I removed the self.create_with_password and manually type in the password in the form, it works. So i guess the error must be in the self create password, it seems like doesn't save the record. By the way I'm using Rails 5.0. Any idea to solve this?
Hey #ternggio Welcome to community.
Account can't be blank.
This error appear due to belongs_to statement in user.rb.
In rails > 5 belongs_to is by default required, You can set as optional with marking optional: true.
belongs_to :account, :inverse_of => :users, optional: true
and remove below line.
validates :account, :presence => false
Hope, this will help you.

Update column through expiry in rails 4

An user should vote for a celebrity only once in 24 hours. So I need to update a votes column in user table. What I am doing here is that I am checking whether the current user has voted. If not I am allowing him to vote.
My models are
vote.rb
attr_accessible :celebrity_id, :user_id
belongs_to :user
belongs_to :celebrity, counter_cache: true
user.rb
attr_accessible :email, :name, :uid, :provider, :vote
has_many :votes
celebrity.rb
attr_accessible :name, :gender, :category_id, :image, :votes_count
belongs_to :user
belongs_to :category
has_many :votes
My controller
#celebrities = Celebrity.find(params[:id])
#vote = current_user.votes.build(celebrity_id: #celebrities.id, :id => params[:vote])
respond_to do |format|
if current_user.vote != true
current_user.vote = true
current_user.save
#vote.save
format.json { render json: #vote, status: :created }
else
format.json { render json: #vote.errors, status: :unprocessable_entity}
end
end
But, how can I set vote column in user table to zero every 24 hrs comparing to votes table created_at time

Carrierwave not uploading - no error shown

I've been working on this all night and it makes no sense. I'm adapting an old photo web app to have albums in it. I made "fails" (basically images) a nested resource of albums. I am using carrierwave to upload files to an S3 bucket.
the weird thing is: the upload works perfectly fine for the album model (album image), but it doesn't upload for the fail model.
I don't see why it'd be a problem that it's a nested resource now. It's not a problem displaying it's that for some reason, it goes through the form fine, passes validations fine, no errors are thrown, it redirects to fails#index like it was successful, but there is nothing in the db or in S3.
Code is below. All code at https://github.com/spq24/failboard
Fail Model
class Fail < ActiveRecord::Base
attr_accessible :description, :image, :remote_image_url, :fail_title, :tag_list, :processed, :youtube_url, :album_id
make_voteable
acts_as_taggable
belongs_to :album
mount_uploader :image, ImageUploader
validates :description, length: { :maximum => 200 }
validates :album_id, presence: true
validates :image, presence: true
validates :fail_title, presence: true, length: { :maximum => 50 }
validate :maximum_amount_of_tags
def maximum_amount_of_tags
number_of_tags = tag_list_cache_on("tags").uniq.length
errors.add(:base, "Please only add up to 5 tags") if number_of_tags > 5
end
before_save :update_attachment_attributes
def update_attachment_attributes
if image.present? && image_changed?
self.content_type = image.file.content_type
self.file_size = image.file.size
end
end
def next
user.fails.where("id > ?", id).order("id ASC").first
end
def prev
user.fails.where("id < ?", id).order("id DESC").first
end
end
Album Model
class Album < ActiveRecord::Base
attr_accessible :name, :image, :image_url, :created_at
belongs_to :user
has_many :fails, dependent: :destroy
mount_uploader :image, ImageUploader
validates :user_id, presence: true
validates :image, presence: true
validates :name, presence: true, length: { :maximum => 50 }
before_save :update_attachment_attributes
def update_attachment_attributes
if image.present? && image_changed?
#self.content_type = image.file.content_type
#self.file_size = image.file.size
end
end
def next
user.fails.where("id > ?", id).order("id ASC").first
end
def prev
user.fails.where("id < ?", id).order("id DESC").first
end
end
Fails Controller
def new
#fail = Fail.new(:album_id => params[:album_id])
respond_to do |format|
format.html # new.html.erb
format.json { render json: #fail }
end
end
def create
#fail = Fail.new(params[:fail])
respond_to do |format|
if #fail.save
format.html { redirect_to #fail.album, notice: 'You added a new photo!' }
format.json { render json: #fail, status: :created, location: #fail }
else
format.html { render action: "new" }
format.json { render json: #fail.errors, status: :unprocessable_entity }
end
end
end
routes.rb
resources :albums do
get 'tags/:tag', to: 'fails#index', as: :tag
resources :fails do
member do
post :up_vote
end
end
Debug Hash (this turns red when I try to upload, but I don't see anything that would cause the error)
Here is the debug info:
{"utf8"=>"✓", "authenticity_token"=>"Hz6Gl95ultYDNIEjQioIckB8JXQwhiMxXIM9jrfqd5Q=", "fail"=>{"fail_title"=>"tester", "image"=>#<ActionDispatch::Http::UploadedFile:0x56195e8 #original_filename="pic19.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"fail[image]\"; filename=\"pic19.jpg\"\r\nContent-Type: image/jpeg\r\n", #tempfile=#<File:C:/Users/Kinertia/AppData/Local/Temp/RackMultipart20131125-10428-m2ktp2>>, "description"=>"", "tag_list"=>"test"}, "commit"=>"Create Fail", "controller"=>"fails", "action"=>"index"}
If there is anything else needed please let me know and I will put it here. Thank you for all the help!
Have you tried validating the integrity or processing of the fail image?
validates_integrity_of :avatar
validates_processing_of :avatar
validates_download_of :avatar
By default it fails silently, which kinda sucks.
I also recommend trying to create the record in the rails console, which can help to isolate the problem to either the model or view/controller layers. In your case this would look something like:
Fail.create!(
image: File.open('path/to/known/file.jpg'),
album_id: 1,
fail_title: 'Title'
)

Rails behaving strange

I have rails version 3.2.13 and ruby version 1.9.3.
I have caught into very strange and interesting situation.
In my application have a model 'Product' with custom validator.
product.rb
class Product < ActiveRecord::Base
attr_accessible :description, :name, :price, :short_description, :user_id
validates :name, :short_description, presence: true
validates :price, :numericality => {:greater_than_or_equal_to => 0}
validate :uniq_name
belongs_to :user
belongs_to :original, foreign_key: :copied_from_id, class_name: 'Product'
has_many :clones, foreign_key: :copied_from_id, class_name: 'Product', dependent: :nullify
def clone?
self.original ? true : false
end
private
#Custom validator
def uniq_name
return if clone?
user_product = self.user.products.unlocked.where(:name => self.name).first
errors[:name] << "has already been taken" if user_product && !user_product.id.eql?(self.id)
end
end
In products controller's create action when I am trying to create new product
def create
#product = current_user.products.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
#product.errors[:image] = "Invalid file extension" if #product.errors[:image_content_type].present?
format.html { render action: "new" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
Custom validator is being called when this line executed #product = current_user.products.new(params[:product]) and line # 2 of custom validator giving me error
undefined method `products' for nil:NilClass
I have inspected product object in custom validator but user_id is nil.
Why user_id is not being autoassigned?
Your help will be appreciated :)
So ... bypassing your question. Why aren't you just validating the uniqueness of name?
validates_uniqueness_of :name, :unless => :clone?
try to change .new to .build
#product = current_user.products.build(params[:product])
and be sure that you have relation in your User model
Class User < ActiveRecord::Base
has_many :products

Resources