Reputation: 25
I have a movie app that searches OMDb API database and populates the search results in my app. I've taken those search results and iterated over them to create movie cards for each result.
In this movie cards, I have a button to 'Add Movie To List', which would allow the user to press it and add it to lists that are already created. The user would be able to specify which list, then add it to the database.
I'm not sure how to get that action to work. Can anyone point me in the right direction?
My search.html.erb page:
<div class="card-deck text-center" id="card-deck">
<% if @movies %>
<% @movies.each do |m| %>
<div class="card">
<img src= "<%= m["Poster"] %>" alt="No poster found." class="card-img-top">
<div class="card-body">
<h5 class="card-title"><%= m["Title"] %></h5>
<p class="card-text"><%= m["Year"] %></p>
</div>
<div class="card-footer">
<div class="btn-top">
<span class="btn-group">
<%= button_to "Add Movie To List", class: 'btn btn-primary btn-sm btn-space' %>
</span>
</div>
</div>
</div>
<% end %>
<% end %>
</div>
How would I route that button to a certain controller action, then use the info from the API to create a new instance of a movie, then add it to a list?
My searches_controller.rb:
class SearchesController < ApplicationController
def index
@list = List.all.select(:id, :name)
@movie = Movie.new
end
def omdb
@movie = Movie.new
@list = List.all.select(:id, :name)
conn = Faraday.new(:url => 'http://www.omdbapi.com')
@resp = conn.get do |req|
req.params['apikey'] = ENV['OMDB_API_KEY']
req.params['s'] = params[:movie]
end
body = JSON.parse(@resp.body)
if @resp.success?
@movies = body["Search"]
else
@error = "There was a timeout. Please try again."
end
render 'index'
end
end
Routes:
Rails.application.routes.draw do
resources :lists, :movies
get '/search', to: 'searches#index'
post '/search', to: 'searches#omdb'
root 'lists#index'
end
My button on my Search index.html.erb to add movie to list to bring up modal popup:
<div class="btn-top">
<button class="btn btn-primary btn-sm add-movie" movie-id="m['imdbID']" type="button" data-toggle="modal" data-target="#movielistmodal">Add Movie To List</button>
</div>
And my modal body code:
<div class="modal-body">
<%= form_for @movie, method: :post, url: 'add_api_movie_to_list' do |f| %>
<%= hidden_field_tag :movie_id, { id: "movie-id" } %>
<% @list.each do |list| %>
<%= f.label :name, list.name %>
<%= f.radio_button :list_ids, list.id %>
<% end %>
<%= f.submit class: 'btn btn-primary btn-space btn-sm' %>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
Add API movie to database controller action:
def add_api_movie_to_list
conn = Faraday.new(:url => 'http://www.omdbapi.com')
@resp = conn.get do |req|
req.params['apikey'] = ENV['OMDB_API_KEY']
req.params['i'] = params[:movie_id]
end
body = JSON.parse(@resp.body)
movie_params = { title: body["Title"], genre: body["Genre"], year: body["Year"], poster: body["Poster"], plot: body["Plot"], director: body["Director"] }
movie_params.merge(params[:movie])
@movie = Movie.new(movie_params)
if @movie.save
redirect_to movie_path(@movie)
else
flash[:error] = "Unable to save movie. Try again."
render 'search'
end
end
Upvotes: 0
Views: 742
Reputation: 754
Since the movies are saved to your database, you can set up a route for a custom action on your movies, in combination with link_to
.
An example if you have resources :movies
defined you can do something like this ->
In routes.rb
resources :movies do
post '/add_to_list', action: 'add_to_list'
end
In movies_controller.rb
->
def add_to_list
@movie = Movie.find(params[:movie_id]
@movie.add_to_list
end
add_to_list
can be defined in your Movie
model to whatever you need to do with it.
Inside your view (search.html.erb
) instead of button_to
, you can use link_to
like this ->
<%= link_to 'Add Movie To List', movie_add_to_list_path(m), class: "btn btn-primary btn-sm btn-space", method: :post %>
This is the quick solution on your question: "How would I route that button to a certain controller action".
For this part -> "Then use the info from the API to create a new instance of a movie, then add it to a list?" I will guess a few things:
If this is the case, then you can create a model concern that will contain some logic to interact with OMDB service object
For example, that custom method I put above add_to_list
can be defined in that concern.
If you need more info on how to do that, you can contact me.
Upvotes: 0
Reputation: 1227
Things you've to do to achieve this functionality.
def search
so that you can access it on the search.html.erbI'm assuming you already have 2 models with similar relationships:
Class MovieList
has_many :movies
end
Class Movie
belongs_to :movie_list
end
in your movies_controller or any other controller where you've defined def search
method.
add this line.
def search
#your pre existing code
#add the following line
@movie_list = MovieList.all.select(:id, :name)
end
in search.html.erb
add html code for modal.
in modal body add code for a form where you'll be storing the movie_id
in the hidden field and checkboxes for selection of list.
<%= form_for :movie, method: :post, url: 'path_of_the_method' do |f| %>
<%= hidden_field_tag :movie_id, { id: "movie-id" } %>
<% @movies_list.each do |item| %>
<%= f.radio_button :movie_list_id, item.id %>
<% end %>
<%= f.submit %>
<% end %>
specify this route in the routes.rb
now,
for each movie in search result there's a button associated to it. Let's override it's functionality.
<%= button_to "Add Movie To List", class: 'btn btn-primary btn-sm btn-space add-movie', 'data-movie-id': m['id'] %>
NOTE: I'm guessing you're getting uniq movie_id
for each movie.
JQuery:
for making it work you can define it at the end of search.html.erb
<script>
$('.add-movie').click(function(e){
e.preventDefault();
//Let's assume the id of the Modal (popup) is #list-modal
$('#movie-id').val($(this).data('movie-id')); //id of the hidden field
$('#list-modal').modal('show');
});
</script>
now in controller method you've just defined for saving the form value
let's assume the method name is create_movie
or if you're using resources you can directly write create
def create_movie
#API to fetch details of the movie id you've passed in `params[:movie_id]`
#movie = API call
#select the attributes you'll be saving in the database. eg:
hash_params = { title: movie['title'], name: movie['name'] }
hash_params.merge(params[:movie])!
movie = Movie.new(hash_params)
if movie.save
#redirect with success message
else
#redirect with failure message
end
end
I've tried to explain in the best possible manner. :P You can get a hint with it what you'll have to do. In case you still need help, just let me know.
Upvotes: 1