I'm calling an array of recommended products (based on the predictor-gem) and want to exclude the products of the current_user from that set. I think that I'm using the proper condition for it (" != ?") but just not in the correct way. #products_rec should give that final array.
Here's the specific code in my product_controller.rb:
recommender = ProductRecommender.new
products = current_user.products
#product_rec = (recommender.similarities_for("product-#{#product.id}")).map {|el| el.gsub(/(.*\-)[^\d]*/, "")}
#products_rec = Product.find(#product_rec, :conditions => ["id != ?", products.id])
and here's my model, product.rb:
class Product < ActiveRecord::Base
include Reviewing
include PublicActivity::Model
tracked
extend FriendlyId
friendly_id :name, use: [:slugged, :finders]
belongs_to :category
belongs_to :benefit
has_many :subscriptions
has_many :users, through: :subscriptions
has_many :benefits
has_many :projects, through: :benefits
belongs_to :user
validates :name, presence: true, length: { maximum: 200 }
validates :gtin, presence: false
validates :content, presence: false, length: { maximum: 2000 }
validates :video, presence: false
validates :tag, presence: false
validates :project, presence: false
validates :category, presence: false
validates :user, presence: false
has_attached_file :image, :styles => { :medium => "680x300>", :thumb => "170x75>" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
I want to exclude the products from the current_user, based on the users through subscriptions (see model).
How can I get this to work, any ideas?
Final code:
Based on the answer of #Humza, I've added the following working code to my product_controller.rb:
recommender = ProductRecommender.new
products = current_user.products.select("id")
#product_rec = (recommender.similarities_for("product-#{#product.id}")).map {|el| el.gsub(/(.*\-)[^\d]*/, "")}
#products_rec_array = Product.find(#product_rec)
#products_rec = Product.where(id: #products_rec_array).where.not(id: products)
To find products with id not in array, you must do this:
array = current_user.products.pluck(:id)
Product.where('id NOT IN (?)', array) # '?' is surrounded by paranthesis
But since a product belongs to a user, you can simply do
Product.where('user_id != ?', current_user.id)
You can also use the not method like so:
Product.where.not(id: array)
Product.where.not(user_id: current_user.id)
Edit:
If you want the base products to be from some other list, this can help:
base_product_ids = some_list.map(&:id) # assuming this is an Array
Product.where(id: base_product_ids).where.not(user_id: current_user.id)
If some_list was an ActiveRecord::Relation, you could have simply done:
some_list.where.not(user_id: current_user.id)
Related
I have method called check_field, purpose of this method is for checking is there multiple value when input form.
I was think maybe I can check with multiple array on rails. I found some code on this link to check duplicate value inside array. So, I implement that method (difference) on my model
, but I got stuck when implement to my Model, the methot won't called.
NoMethodError (undefined method `difference' for ["vvvv", "vvvv", "xxxxxxxxx", "xxxxxxxxx"]:Array):
here my Code.
class Model < ApplicationRecord
has_many :child_models, -> { where(active: true) }, :foreign_key => :model_id, :dependent => :destroy
accepts_nested_attributes_for :child_models, :allow_destroy => false
before_validation :check_field, :before => [:create]
def check_field
all_field = Array.new
child_models.each do |data|
all_field << data.field
end
uniq_field = all_field.uniq
result = uniq_field - all_field.difference(uniq_field)
errors.add(:field, "Field must be Different")
end
def difference(other)
h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
the field that I want to validate is on child_models,
class ChildModel < ApplicationRecord
validates :field, presence: { message: "Field" + I18n.t("sys_err_is_required"), :if => :active?, :scope => [:active] }, :uniqueness => { :message => 'Field is already exist', :if => :active?, :scope => [:active], :case_sensitive => false }
end
I was try to put check_field method on ChildModel, it didn't work, because the parameters can be read on Model class.
so then any solution for this case?
thanks.
you should use self.difference to call your method, because it is a classmethod. see https://dev.to/adamlombard/ruby-class-methods-vs-instance-methods-4aje
...
result = self.difference(uniq_field)
I'm using react for the client side and rails for the server.
When trying to link the post to its username I get 'undefined'.
If I try user={post.user_id} to get the user_id, it works fine, but I want to show the username.
PostList.jsx
{posts.map((post) => (
<>
<Post
key={post.id}
title={post.title}
content={post.content}
user={post.user.username}
id={post.id}
getPosts={getPosts} />
</>
Post.jsx
const Post = ({title, content, user, id, getPosts}) => {
return (
<div className='post-container'>
<div className='post-header'>
<div className='post-title-user'>
<h2>{title}</h2>
<span>Posted by: #{user}</span>
</div>
</div>
<p>{content}</p>
</div>
)
}
export default Post
schema.rb
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "user_id", null: false
t.index ["user_id"], name: "index_posts_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "username"
t.string "password_digest"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
user.rb
class User < ApplicationRecord
has_secure_password
has_many :posts
end
post.rb
class Post < ApplicationRecord
belongs_to :user
end
I think you should use active_model_serializers gem
Step1: add gemfile gem 'active_model_serializers'
Step2: bundle
Step3: rails g serializer post
In posts_controller.rb
class PostsController < ApplicationController
def index
posts = Post.all
render json: {
message: 'Get posts',
data: ActiveModel::Serializer::CollectionSerializer.new(posts, each_serializer: PostSerializer)
}
end
end
In post_serializer.rb
class PostSerializer < ActivieModel::Serializer
attributes :id, :title, :content, :username
def username
#You try byebug and check object
object.username
end
end
I am working on a post request in which the user chooses from a list of tags and makes combinations of tags. The combination of tags should then be posted. Nothing should get changed in the Tag table.
These are the models:
models.py
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
"""Return a human readable representation of the model instance."""
return self.name or ''
#property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Combination(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, null=True)
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, null=True)
tag_id = models.ManyToManyField(Tag, null=True)
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
objects = models.Manager()
def __str__(self):
return str(self.tag_id) or ''
This is the serializer for Combination.
serializers.py
class CombinationSerializer(serializers.ModelSerializer):
tag_id = TagWithIdSerializer(many=True, required=False, write_only=False)
resource_id = serializers.PrimaryKeyRelatedField(queryset=Resource.objects.all(),
required=True,
source='resource',
write_only=False)
gameround_id = serializers.PrimaryKeyRelatedField(queryset=Gameround.objects.all(),
required=False,
source='gameround',
write_only=False)
user_id = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all(),
required=False,
source='user',
write_only=False)
class Meta:
model = Combination
depth = 1
fields = ('id', 'user_id', 'gameround_id', 'resource_id', 'tag_id', 'created', 'score')
def create(self, validated_data):
user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
score = 0
tag_data = validated_data.pop('tag_id', None)
combination = Combination(
user=user,
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
created=datetime.now(),
score=score
)
combination.save()
for tag_object in tag_data[0]:
combination.tag_id.add(tag_object)
return combination
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['tag_id'] = TagWithIdSerializer(instance.tag_id.all(), many=True).data
return rep
I have tried posting the following JSON object to the database:
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [{"id": 2014077506, "name": "corwn","language": "en"}]
}
I am getting a ValueError: Field 'id' expected a number but got 'name'.
How can I fix this issue?
you need to provide tag id for each tag not all tag data,
Try like this
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [2014077506,2014077507]
}
Is there a way to stop a model in django allowing an empty model to be saved?
e.g. I have a simple contact form
class Contact(models.Model):
alphabetical = RegexValidator(r'^[a-zA-Z]*$', 'Only alphabetical characters
are allowed', 'Invalid input')
name = models.CharField(max_length=200, validators=[alphabetical])
email = models.EmailField(validators=[EmailValidator, ])
subject = models.CharField(max_length=200)
message = models.CharField(max_length=250)
created_date = models.DateTimeField(auto_now_add=True)
How can I prevent an empty model being saved? e.g. in the django shell I can do
contact = Contact()
contact.save()
This gives a model with all blank values saved.
for validation you have to use django.forms. django forms will manage the validation part:
for eg: if your model.py is:
class Contact(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
subject = models.CharField(max_length=200)
message = models.CharField(max_length=250)
created_date = models.DateTimeField(auto_now_add=True)
now create a view in views.py :
from django.forms import modelformset_factory
from django.shortcuts import render
from myapp.models import Contact
def manage_contacts(request):
ContactFormSet = modelformset_factory(Contact, fields=('name', 'email', 'subject', 'message'))
if request.method == 'POST':
formset = ContactFormSet(request.POST)
if formset.is_valid(): # check the validation for blank fields
formset.save()
# do something.
else:
formset = ContactFormSet()
return render(request, 'manage_contacts.html', {'formset': formset})
create a template in templates/manage_contacts.html:
<form method="post">
{{ formset }}
</form>
I have a user model with Paperclip for avatars and I need to be able to return the image_url for each size (small, medium, large) using RABL.
In mongoid model i would simply do self.avatar(:original) but now nothing works, I just get an empty response in the attachment
"user" : {
"id" : "50b204e10eae9c55fa000028",
"paperclip::attachment" : {},
"name" : "My Name"
}
/models/user.rb
has_mongoid_attached_file :avatar,
:styles => {
:original => ['1000x1000>', :jpg],
:small => ['64x64#', :jpg],
:medium => ['250x250', :jpg],
:large => ['500x500>', :jpg]
}
/views/posts/base.json.rabl
child :user do
attributes :id, :name
child :avatar do
attributes :original
end
end
Try this:
child :user do
attributes :id, :name
node :avatar_original do |u|
u.avatar(:original)
end
end