Create a post with many-to-many relationship in Ruby on Rails - ruby-on-rails

I have a structure very much for between category and yell. What I do is qeuro a call on POST type API with the following parameters:
{
"user_id":"1",
"title":"primeito",
"desciption":"de_novo",
"categories":[{"name":"eletro"},{"name":"domestic"},{"name":"new_category"}],
"yell_type":"novo",
"price":"10,00",
"payment_type":"boleto"
}
My structure is as follows:
My model yell:
#yell.rb
class Yell < ActiveRecord::Base
belongs_to :user, inverse_of: :yells
has_and_belongs_to_many :categories
end
model category:
#category.rb
class Category < ActiveRecord::Base
has_and_belongs_to_many :yells
end
method crete in controller yell:
#yells_controller.rb
def create
#yell = Yell.new(yell_params)
params[:categories].each do |rel|
#category = Category.find_by_name(rel[:name])
if #category
#only creates the relationship
else
#yell.categories.build(name: rel[:name]) #creates the relationship and category
end
end
if #yell.save
render json: #yell, status: :created, location: api_yell_path(#yell)
else
render json: #yell.errors, status: :unprocessable_entity
end
end
...
private:
def yell_params
params.require(:yell).permit(:title, :desciption, :price, :payment_type, :user_id, :yell_type, :categories)
end
So I created the table
class CreateCategoriesYellsJoinTable < ActiveRecord::Migration
def self.up
create_table :categories_yells, :id => false do |t|
t.integer :category_id
t.integer :yell_id
end
add_index :categories_yells, [:category_id, :yell_id]
end
def self.down
drop_table :categories_yells
end
end
I can make him create the categories, but does not know how to create only the relationship. Agluem can help me is the comment #only creates the relationship?
I need to do this check because the category name is unique
Also if someone know something more elegant way to do this, I accept suggestions

I am not quite sure I understood the last paragraph, but I think you need an intermediate table to join the two models first.
You would need to create a table like this:
class CreateCategoriesAndYells < ActiveRecord::Migration
def change
create_table :categories_yells, id: false do |t|
t.belongs_to :category, index: true
t.belongs_to :yell, index: true
end
end
end
Then you would need to update your controller to say something like this:
#yell.categories.build(category_params)
You would need also to pass the category parameters to the controller.

In order to do so I had to create a model to join my table:
model category_yell.rb
class CategoriesYell < ActiveRecord::Base
belongs_to :category
belongs_to :yell
end
and create my method was as follows:
def create
##yell = Yell.new(yell_params.except(:categories))
#yell = Yell.new({title: params[:title], desciption: params[:desciption], price: params[:price], user_id: params[:user_id], yell_type: params[:yell_type]})
if #yell.save
Array(params[:categories]).each do |rel|
#category = Category.find_by_name(rel[:name])
if #category
#categories_yells = CategoriesYell.new(category_id: #category.id, yell_id: #yell.id)
if #categories_yells.save
#yell.categories.build(id: #category.id, name: rel[:name])#only creates the relationship
else
render json: {status: 1, message:"relationship categoy not create", data: #yell.errors}, status: :unprocessable_entity
end
else
#yell.categories.create(name: rel[:name]) #creates the relationship and category
end
end
render json: {status: 0, message:"sucess", data: #yell}, status: :created
else
render json: {status: -1, message:"error", data: #yell.errors}, status: :unprocessable_entity
end
end

Related

How to assign a user id to a record in the backend?

I want to make sure that when I create a record in the front end, the user id of the user who created it is automatically assigned to this record. What should I do in the backend if I want the id of the authorized user to be automatically assigned to the record when creating the record? For authorization I use gem 'devise_token_auth'.
notebooks_controller.rb:
class NotebooksController < ApplicationController
before_action :set_notebook, only: [:show, :update, :destroy]
def index
#notebooks = Notebook.all
render json: #notebooks
end
def show
render json: #notebook
end
def create
#notebook = Notebook.new(notebooks_params)
if #notebook.save
render json: #notebook, status: :created, location: #notebook
else
render json: #notebook.errors, status: :unprocessable_entity
end
end
def update
if #notebook.update(notebooks_params)
render json: #notebook
else
render json: #notebook.errors, status: :unprocessable_entity
end
end
def destroy
#spr_contract_solution.destroy
end
private
def set_notebook
#notebook = Notebook.find(params[:id])
end
def notebooks_params
params.require(:notebook).permit!
end
end
notebook.rb:
class Notebook < ApplicationRecord
belongs_to :user
end
...._create_notebooks.rb
class CreateNotebooks < ActiveRecord::Migration[5.1]
def change
create_table :notebooks do |t|
t.string :title
t.text :description
t.boolean :is_active
t.references :user, foreign_key: true
t.timestamps
end
end
end
First, #Subash is right, you need to pass the list of parameters to the permit method in notebook_params (note that maybe you would want to use permit instead of permit!), for example:
params.require(:notebook).permit :name, :text, :any_other_attribute_you_are_saving
Then, to answer your question, you could do something like this in the create action:
#notebook = Notebook.new(notebooks_params)
#notebook.user = current_user #Assuming you have this method available
Assuming you have has_many :notebooks in your user model, this is a popular idiom for doing what you want:
#notebook = current_user.notebooks.build(notebook_params)
add
#notebook.user = current_user
after
#notebook = Notebook.new(notebooks_params)

How to associate a subscriber to an event

I'm trying to make that a subscriber, sub to an certain event
with the following url per example:
http://localhost:3001/events/1/subscribers/new
but I don't know how to associate event_id when creating a new subscriber
for the moment i'm getting this error:
Couldn't find Event with 'id'=
in the routes:
resources :events do
resources :subscribers #url/events/:events_id/subscribers/new
end
resources :events
root 'events#index'
in the subscribers controller:
def show
end
# GET /subscribers/new
def new
#puts "Look for me in console\n"
#puts params.inspect
#event = Event.find(params[:events_id])
#subscriber = #event.Subscriber.new
end
# GET /subscribers/1/edit
def edit
end
# POST /subscribers
# POST /subscribers.json
def create
#event = Event.find(params[:order_id])
#subscriber = #event.Subscriber.new order_params
##subscriber = Subscriber.new(subscriber_params)
respond_to do |format|
if #subscriber.save
SubsMailer.new_subscriber(#subscriber).deliver
format.html { redirect_to #subscriber, notice: 'Subscriber was successfully created.' }
format.json { render :show, status: :created, location: #subscriber }
else
format.html { render :new }
format.json { render json: #subscriber.errors, status: :unprocessable_entity }
end
end
end
in the new.html.erb:
<h1>New Subscriber</h1>
<%= render 'form', subscriber: #subscriber %>
<%= link_to 'Back', subscribers_path %>
model association:
event.rb:
class Event < ApplicationRecord
has_many :subscribers, dependent: :destroy
end
subscriber.rb:
class Subscriber < ApplicationRecord
belongs_to :event
validates :email, presence: true,
format: /\A\S+#\S+\z/,
uniqueness: { case_sensitive: false }
end
Well, I think this documentation will help you to understand what you need to do.
If briefly at first you need to change your models. You could have many to many for Event -> Subscriber association or one to many. One to many is the simplest to show so you need to add this to your Subscriber model:
belongs_to :event
And this to your Event model:
has_many :subscribers
Add new migration:
def change
remove_column :subscribers, :events_id
remove_column :subscribers, 'Event_id'
add_column :subscribers, :event_id, :integer
end
Then in your controller, you should change method calls, as Subscriber is a class, not the method.
def new
#event = Event.find(params[:event_id])
#subscriber = #event.subscribers.build
end
And you should be sure that in your database you have Event with this id.
To check it you can try to debug your controller code:
def new
puts "Event ids: " + Event.all.map(&:id).inspect
#event = Event.find(params[:event_id])
#subscriber = #event.subscribers.build
end
In your logs you should have something like:
Event ids: [1]
I think you just have a typo in your new method. You call params[:eventS_id] when it should be params[:event_id]. Also you don't properly reference your association. it should be event.subscribers.new:
def new
#puts "Look for me in console\n"
#puts params.inspect
#event = Event.find(params[:event_id])
#subscriber = #event.subscribers.build
end
Migration:
def up
change_table :subscribers do |t|
t.remove :Event_id
t.references :event
end
end
def down
change_table :subscribers do |t|
t.remove :event_id
t.add :Event_id, :integer
end
end
Keep me posted whether this helps and if you have any additional issues

Rails, How to show all product by category search feature?

Now I want to add some add search feature to my project. I have 2 table about product and category, then i'm using one to many relation. I get stuck when i want to search my product by their categories. Here my code:
products_controller.rb:
def index
#product = Product.all
render json: #product, status: :ok
end
def search
#category = Category.find(params[:category_id])
#product = #category.products
render json: #product, status: :ok
end
def show
render json: #product, status: :ok
end
routes.rb
Rails.application.routes.draw do
namespace :v1 do
resources :products
resources :categories
post 'products/search', to: "products#search"
get 'products/search', to: "products#search"
end
end
model category.rb
class Category < ApplicationRecord
has_many :products
end
model product.rb
class Product < ApplicationRecord
belongs_to :category
end
my product table field
t.integer :category_id
t.string :product_name
t.string :company
t.text :description
t.string :logo_img
t.string :web_link
my table category field
t.string :category_name
t.string :status
How should it work for category show all their products?
Thanks for your help
add your categories_controller.rb like following
categories_controller.rb
def show
category = Category.find(params[:id])
render json: category.products, status: :ok
end
end
and visit /categories/:id url

Rails 3.2 Associations and :include

I have some troubles to make an association between 2 tables.
I have Users who can write Posts
Here is my migration file :
class LinkUsersAndPosts < ActiveRecord::Migration
def change
add_column :posts, :user_id, :integer
add_index :posts, :user_id
end
end
My models :
class Post < ActiveRecord::Base
attr_accessible :content, :title
belongs_to :user
end
class User < ActiveRecord::Base
attr_accessible :email, :login, :password, :password_confirmation, :rights
has_many :posts
end
My controller :
class PostsController < ApplicationController
respond_to :json
def index
#posts = Post.includes(:user).all
respond_with #posts
end
def create
#post = Post.new(params[:post])
#post.user = current_user
if #post.save
render json: #post, status: :created, location: #post
else
render json: #post.errors, status: :unprocessable_entity
end
end
end
The posts is correctly created, the user_id is set all is fine.
The problem is when i want to retrieve the list of posts including user, the list of posts is retrieve, but i havn't any data on the user except his id.
Response :
[
{
"content":"jksdjd",
"created_at":"2013-08-31T09:03:01Z",
"id":11,"title":"kdjs",
"updated_at":"2013-08-31T09:03:01Z",
"user_id":4
},
{
"content":"tez2",
"created_at":"2013-08-31T09:16:45Z",
"id":12,
"title":"test2",
"updated_at":"2013-08-31T09:16:45Z",
"user_id":4
}
]
By default a JSON response won't return any associated models. You need to specify the other models you want returned. So in your case, you can do this:
render json: #post => #post.to_json(:include => :user), status: :created, location: #post
Also see:
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
Rails Object Relationships and JSON Rendering

Basic database association

I am attempting to associate 2 models - Athletes and Results
They have the following fields:
Athletes - :name :year :gender
Results - :name :event :performance
I have added belongs_to :athlete to results.rb & added has_many :results to athletes.rb
I would like to use the :name attribute to act as the primary key used to associate the two models as the intention is for all athletes to be uploaded initially and then just use the results input for the remainder of the season.
I have edited the results_controller to the following:
def create
#this was the initial code....
##result = Result.new(params[:result])
# This is the new code to try set up an association
#athlete = Athlete.where('name = ?', 'Peter')
#result = #athlete.results.create(params[:result])
respond_to do |format|
if #result.save
format.html { redirect_to #result, notice: 'Result was successfully created.' }
format.json { render json: #result, status: :created, location: #result }
else
format.html { render action: "new" }
format.json { render json: #result.errors, status: :unprocessable_entity }
end
end
end
This however produces the error undefined method 'results' for #<ActiveRecord::Relation:0x36a2b28>. I was also hoping to use the line #athlete = Athlete.where("name = ?", params[:name]) however it keeps yielding a NULL parameter value...
Is anyone able to point me in the correct direction please?
Extra information:
Results migration
class CreateResults < ActiveRecord::Migration def change
create_table :results do |t|
t.string :name
t.string :event
t.decimal :performance
t.timestamps
end
#add in new line here
add_index :results, :name
end end
Athletes migration
class CreateAthletes < ActiveRecord::Migration
def change
create_table :athletes do |t|
t.string :name
t.integer :year
t.string :gender
t.timestamps
end
end
end
Result.rb:
class Result < ActiveRecord::Base
belongs_to :athlete
end
Athlete.rb
class Athlete < ActiveRecord::Base
has_many :results
end
The problem is that Athlete.where('name = ?', 'Peter') returns ActiveRecord::Relation object. Either use
Athlete.where('name = ?', 'Peter').first
or the dynamic find method
Athlete.find_by_name('Peter')
Edit
Also make sure you add t.references :athlete to your results table.
Your results table needs to store the athlete_id.
create_table :results do |t|
t.references :athlete
t.string :name
t.string :event
t.decimal :performance
t.timestamps
end
The references will create the foreign key association using the rails conventions (which in this case is athlete_id)

Resources