Rendering associations in JSON with Rails - json

I have 2 models Products and kits, each with a HABTM relationship through a JOIN table KitsProducts
create_table "kits_products", id: false, force: :cascade do |t|
t.bigint "product_id", null: false
t.bigint "kit_id", null: false
end
respond_to do |format|
format.html { render 'new', layout: "builder" }
format.json do
render json: [
products: #kits
]
end
format.js
end
I'm rendering a JSON with my kits controller:
#kits = Kit.joins(:products).order(created_at: :asc)
I want the output to include the product_ids associated with that kit (Desired output:)
"id":1,
"name":"Kit 1",
--> I'M MISSING THIS: "product_ids": [1,2,3,4],
"created_at":"2022-07-03T13:36:46.251Z",
"updated_at":"2022-07-03T13:37:39.010Z",
I tried with Kit.joins(:products) with no luck.
¿Any ideas?
Thanks!

I finally got it working by using as_json and includes in my respond block:
kits: #kits.as_json(include: :products)

Related

Need help creating a GET route

I need help implement a route to fetch all blog posts by author_ids.
The post that we're fetching needs to have at least one of the authors specified in the passed in author_ids parameters. I've created a helper function to help me fetch all blog posts by their ID, Post.get_posts_by_user_id
I also need to sort the posts by query parameters given. Also, I need to delete any duplicated posts as efficiently as possible.
I'm stumped here because of the way author_ids is being given. (I'm extremely new to Ruby)
This is what we should get returned from the route: "posts": [{"id": 1, "likes": 960, "popularity": 0.13, "reads": 50361, "tags": ["tech", "health"], text": "Some text here."}, ... ]
Query parameters expected to be given to this route
Update:
After creating the index method, it seems that it is only getting one post rather than getting all posts that are associated with the passed in authorIds.
def index
posts = current_user
.posts
.where(id: params[:authorIds].split(','))
.order(sort_column => sort_direction)
if posts
render json: { post: posts }, status: :ok
else
render json: {error: posts.errors}, status: :unprocessable_entity
end
end
Test cases
Update 2:
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
I would do it like below.
def index
author_ids_array = params[:ids].to_s.split(',')
Post
.get_posts_by_user_id(author_ids_array)
.order(sort_column => sort_direction)
end
private
def sort_column
allow_list = %w[id reads likes popularity]
params[:sortBy].presence_in(allow_list) || allow_list.first
end
def sort_direction
allow_list = %w[asc desc]
params[:direction].presence_in(allow_list) || allow_list.first
end

Store Join Model Data in Rails [duplicate]

This question already has answers here:
Rails HABTM setup, model object, & join_table insertion controller setup
(2 answers)
Closed 2 years ago.
I'm new to Ruby on Rails, and I'm developing a backend API.
Currently, I got 2 Active Record Models called Book and Genre.
Active Record Model
class Book < ActiveRecord::Base
has_and_belongs_to_many :genres
end
class Genre < ActiveRecord::Base
hast_and_belongs_to_many :books
end
DB Schema Model
create_table :books do |t|
t.string "title"
end
create_table :genres do |t|
t.string "genre"
end
create_join_table :books, :genres do |t|
t.index [:book_id, :genre_id]
t.index [:genre_id, :book_id]
end
REST POST Request
# POST /book
def create
book= Book.new(books_params)
if book.save
render json: {status: 'SUCCESS', message:'Book Saved', data: book},status: :ok
else
render json: {status: 'ERROR', message: 'Booknot saved', data: book.errors}, status: :unprocessable_entity
end
end
private
def books_params
params.require(:book).permit(:title)
end
QUESTION
I'd like to make an HTTP Post request to create a new book with it's genres. I've already tested the book insertion (without genres, just passing the book name), it works perfectly. However I'd also like to add some genre categories.
Both the has_many and has_and_belongs_to_many class methods create a set of _ids setters and getters:
book = Book.new
book.genre_ids = [1, 2, 3]
book.genre_ids == [1, 2, 3] # true
These setters will automatically create and delete rows in the join table. Since ActiveModel::AttributeAssignment maps the hash argument to .new, .update and .create to setters in the model all you need to do is whitelist the genre_ids parameter:
def books_params
params.require(:book).permit(:title, genre_ids: [])
end
Passing an empty array permits an array of permitted scalar values like for example numericals or strings.

Unable to create an entry in the database using create function from the controller

I have two models - CallDetail and Agent. agents table uses foreign key from call_details table.
The schema is pasted below.
ActiveRecord::Schema.define(version: 20170824171227) do
create_table "agents", force: :cascade do |t|
t.integer "agent_id"
t.string "name"
t.integer "CallDetail_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["CallDetail_id"], name: "index_agents_on_CallDetail_id"
end
create_table "call_details", force: :cascade do |t|
t.integer "call_id"
t.string "word"
t.float "start_time"
t.float "end_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
In the above database schema, in addition to the attributes shown rails by default creates CallDetail ID and Agent ID attributes.
My Agents controller create function looks like the following
def create
#agent = Agent.new(agent_params)
respond_to do |format|
if #agent.save
format.html { redirect_to #agent, notice: 'Agent was successfully created.' }
format.json { render :show, status: :created, location: #agent }
else
format.html { render :new }
format.json { render json: #agent.errors, status: :unprocessable_entity }
end
end
end
My models are given below
class CallDetail < ApplicationRecord
end
class Agent < ApplicationRecord
belongs_to :CallDetail
end
When I open localhost:3000/agents and try to create a new entry in the database the following error is shown.
SQLite3::SQLException: no such table: main.CallDetails: INSERT INTO "agents" ("agent_id", "name", "CallDetail_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)
enter image description here
I am new to rails. What am I doing incorrectly here? Please help.
Rails uses inflections to change the names of models (among other things). You are incorrectly referencing CallDetail. When referencing CallDetail, you should use snake_case, not CamelCase. You are calling CallDetail where you should be calling call_detail.
Notice in your schema file that CallDetail got converted to call_details. This is one of the ways Rails uses inflections. You can read about inflections here.

How do I save images via options_for_select with Paperclip and Image Picker on Rails 4?

I'm trying to save images via a form that populates a "Select" field with a number of options. The select form uses Image Picker to change the options when an user clicks on a selected image. When the form is submitted, the selected image should be saved with the Paperclip gem.
I think I just need to point the image url from the selected option to a method that will open it in Paperclip, but I'm not quite sure how to do that. I'm new to Rails, and humbly appreciate anything that will point me in the right direction!
Here's what I have:
_form.html.erb
<%= f.select( :medium_id,
options_for_select(#story.fetched_images.collect{ |v,i| [v, #story.fetched_images.index(v), 'data-img-src' => v ] } )) %>
If I use ":medium", as I would normally do when setting the form input, I get an error that says "ActiveRecord::AssociationTypeMismatch at /stories
Medium(#70334728193840) expected, got String(#70334669736760)", so I have tried using ":medium_id", which displays the value of the selected option instead of the url.
Using ":medium_id" allows the rest of the form fields to save properly without an error, but only the option value is saved for the image, not the image itself.
story.rb
class Story < ActiveRecord::Base
belongs_to :medium
accepts_nested_attributes_for :medium
stories_controller.rb
class StoriesController < ApplicationController
def new
#title = "Submit Story"
#cur_url = "/stories/new"
#story = Story.new
#story.build_medium
end
private
def story_params
p = params.require(:story).permit(
:title, :url, :description, :moderation_reason, :seen_previous,
:merge_story_short_id, :is_unavailable, :medium, :medium_id, :tags_a => [], medium_attributes: [:medium, :image],
)
medium.rb
require "open-uri"
class Medium < ActiveRecord::Base
has_one :story
before_save :image_from_select
def image_from_select(url)
self.image = open(url)
end
end
media_controller.rb
def create
#medium = Medium.new(medium_params)
respond_to do |format|
if #medium.save
format.html { redirect_to #medium, notice: 'Medium was successfully created.' }
format.json { render action: 'show', status: :created, location: #medium }
else
format.html { render action: 'new' }
format.json { render json: #medium.errors, status: :unprocessable_entity }
end
end
end
private
def set_medium
#medium = Medium.find(params[:id])
end
def medium_params
params.require[:medium].permit(:image)
end
end
schema.rb
create_table "stories", force: true do |t|
t.integer "medium_id"
end
create_table "media", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "story_id"
end
I have tried referencing the following without success:
Save image from URL by paperclip
Which is the proper way to upload an image from an external url with Paperclip on rails 4?
http://runnable.com/UnsMH7fYN2V6AAAT/how-to-save-images-by-url-with-paperclip-for-ruby-on-rails-and-upload
https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
Thanks in advance.

Ruby on rails - model missing required attr_accessor for [RAILS]

I'm using ruby on rails and I have some problem with it !
I tried to create a database but it seems not to work !
I generated a model and a database file thank's to the command:
rails g model photos
And here my codes
photos_controller.rb :
class PhotosController < ApplicationController
# POST /photos
# POST /photos.json
def create
#photo = Photo.new(photo_params)
photo_controller.rb
respond_to do |format|
if #photo.save
format.html { redirect_to #photo, notice: 'Photo was successfully created.' }
format.json { render action: 'show', status: :created, location: #photo }
else
format.html { render action: 'new' }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def photo_params
params.require(:photo).permit(:image)
end
end
in the model photo.rb :
class Photo < ActiveRecord::Base
has_attached_file :image
end
in the file 2011234116731_create_photos.rb :
class CreatePhotos < ActiveRecord::Migration
def self.up
add_column :photos, :image_file_name, :string
add_column :photos, :image_content_type, :string
add_column :photos, :image_file_size, :string
add_column :photos, :image_update_at, :string
end
def self.down
remove_column :photos, :image_file_name, :string
remove_column :photos, :image_content_type, :string
remove_column :photos, :image_file_size, :string
remove_column :photos, :image_update_at, :string
end
end
But when I try to load a page which use an element "image" of the model, I ha the following error :
Photo model missing required attr_accessor for 'image_file_name'
Extracted source (around line #27):
POST /photos.json
def create
#photo = Photo.new(photo_params)
respond_to do |format|
if #photo.save
I noticed that the migration seems not to work because in my scheme.rb :
( I've done the rake db:migrate command )
ActiveRecord::Schema.define(version: 20131124183207) do
create_table "photos", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
end
end
Doesn't seem like the migration ran correctly. And it also doesn't look like a migration that would get generated by the rails g model command. It's missing the create_table method. It looks like you previously created the Photo model and then created another migration to add the image fields.
My first hunch would be to try rolling the migration back:
rake db:migrate:down VERSION=2011234116731
Then running rake db:migrate again and check your schema file to make sure all the columns are there.