I am trying to write api code that utilizes the JSON rendered from the controller. I was able to successfully get my desired results locally, but when I push to Heroku parts of my JSON is not rendered correctly.
To put in context, I am trying to create a nested JSON with meal information (name, id, etc) and photo urls. Locally the photo urls render correctly in the JSON. However, on Heroku the photo urls show up as null. On Heroku, I have also tested just rendering the url JSON alone and it is getting the urls correctly.
If you know why it is rendering correctly locally and not on Heroku please let me know. Thank you
I create my JSON the following way:
def api
#meals = Meal.all
#urls = Hash.new
#return_val = Array.new
#sorted_meals = Meal.select('meals.name as meal_name, meals.id as meal_id,
COALESCE(sum(meal_ratings.rating), 0) as meal_rating,
restaurants.id as restaurant_id, restaurants.name as restaurant_name').
joins('LEFT JOIN meal_ratings ON meals.id = meal_ratings.meal_id
LEFT JOIN restaurants ON restaurants.id = meals.restaurant_id').
group('meals.name, meals.id, restaurants.id, restaurants.name').
order('meal_rating DESC').all
#meals.each do |meal|
unless meal.meal_photos.empty?
#urls[meal.id] = {"thumb" => meal.meal_photos[0].photo.url(:thumb), "profile" => meal.meal_photos[0].photo.url(:profile)}
end
end
#sorted_meals.each do |meal|
#return_val.push("id" => meal.meal_id, "name" => meal.meal_name,
"rating" => meal.meal_rating, "restaurant" => meal.restaurant_name,
"restaurant_id" => meal.restaurant_id, "urls" => #urls[meal.meal_id])
end
respond_to do |format|
format.html # show.html.erb
format.json { render json: #return_val } # render json: #url render json: #meals
end
end
The problem was due to Postgres. When I query for a meal_id it returned a string and was not working as a hash key, so I was getting nil. After turning the id string into turn an int everything worked fine. Thanks to the help of Sena this has been resolved.
Related
I am using rails 3 and fragment cache.
Here is my controller code(show method):
if request.format == 'pdf'
render pdf: #design.slug, layout: 'application'
else
**expire_fragment('design_printed_by')**
#design.add_evaluation(:viewed_count, 1, current_user) if current_user && !current_user.evaluated?(#design, :viewed_count)
respond_with #design
end
And here is my view file code(show.html.slim) :
- cache ['design_printed_by', #design], skip_digest: true do
= render partial: 'printed_by', locals: { design: #design }
But when i add new record, this record is not display on page.
I don't know what i am missing.
Is there anything wrong with this code?
Check this link may it help you.
http://guides.rubyonrails.org/caching_with_rails.html#fragment-caching
Backstory: I'm building a site that takes in a Soundcloud URL as part of a post. Currently, I store the link they provide and, when a user loads their feed view, I retrieve the associated image / title / favorite count etc. via my post_helper. I have quickly come to realize that this is not scalable and is hurting load times.
So, what I think I should do (feel free to tell me that there is a better way), is to retrieve the SC/YT metadata on form submit and store it along with the other post data (id, user, content etc.) in the posts' table entry. How would I go about calling the helper methods to retrieve such on form submit and include the metadata in the submitted params?
post_helper.rb excerpt:
def soundcloud_info(soundcloud_url, type)
begin
resolve = scClient.get('/resolve', :url => soundcloud_url)
track_info = scClient.get("/tracks/#{resolve.id}")
rescue Soundcloud::ResponseError => e
%Q{ Error: #{e.message}, Status Code: #{e.response.code} }
end
if type == "title"
%Q{#{track_info['title']}}
elsif type == "image"
%Q{#{track_info['artwork_url']}}
elsif type == "favCount"
%Q{Favorite count: #{track_info['favoritings_count']}}
end
end
post_controler.rb excerpt:
def create
#post = current_user.posts.build(params[:post])
if #post.save
flash[:success] = "Your post was successful!"
redirect_to root_url
else
#feed_items = current_user.feed.paginate(page: params[:page])
render 'static_pages/home'
end
end
So apparently it's pretty straight forward... all I need to do is modify the parameters in the controller before I call #post = current_user.posts.build(params[:post]). My issue was that I was trying to do so in the helper.
I haven't quite adapted the whole thing to get all my required fields, but here's an example of how I have adapted the create method to pull the api URL out if someone submits SoundCloud's embed iframe.
micropost_controller.rb excerpt:
def create
#url = params[:post][:link_html]
if #url[/^.*src="(https|http):\/\/w.soundcloud.com\/player\/\?url=(.*)">/]
params[:post][:link_html] = CGI::unescape($2)
end
#post = current_user.posts.build(params[:post])
if #post.save
flash[:success] = "Your post was successful!"
redirect_to root_url
else
#feed_items = current_user.feed.paginate(page: params[:page])
render 'static_pages/home'
end
end
So I am having an issue where I have this index action that is supposed to return json, but in the browser I am always getting a null response.
Controller
class Admin::Groups::UsersController < Admin::GroupsController
def index
#user_groups = Group.includes(:group_type, :users).where("group_types.group_type_name = ?", 'Users').order("groups.group_name ASC")
render json: #user_groups.to_json(:include => [:group_type, :users], :methods => :enabled)
end
def show
#user_group = Group.includes(:group_type, :users).where("group_types.group_type_name = ?", 'Users').find_by_id(params[:id])
render json: #user_group.to_json(:include => [:group_type, :users], :methods => :enabled)
end
end
Route file
namespace :admin do
namespace :groups do
resources :users, only: [:index, :show] do
get 'enabled', :on => :collection
get 'disabled', :on => :collection
end
end
end
Output of rake routes
admin_groups_users GET /admin/groups/users(.:format) admin/groups/users#index
What is really throwing me off is that when I run the same code that is inside the index action in the rails console, it is outputting exactly what I expected. Also the show action works fine. And just for testing, I added a new route that I just called index2 and copied + pasted the code from the index action into index2 and I got the correct output in the browser.
So it has to be something to do with my route, but I'm not sure what it is?
Edit 1: Add entire output of rake routes
enabled_admin_accounts GET /admin/accounts/enabled(.:format) admin/accounts#enabled
disabled_admin_accounts GET /admin/accounts/disabled(.:format) admin/accounts#disabled
account_owners_admin_accounts GET /admin/accounts/account_owners(.:format) admin/accounts#account_owners
admin_accounts GET /admin/accounts(.:format) admin/accounts#index
admin_account GET /admin/accounts/:id(.:format) admin/accounts#show
enabled_admin_users GET /admin/users/enabled(.:format) admin/users#enabled
disabled_admin_users GET /admin/users/disabled(.:format) admin/users#disabled
admin_users GET /admin/users(.:format) admin/users#index
admin_user GET /admin/users/:id(.:format) admin/users#show
enabled_admin_owners GET /admin/owners/enabled(.:format) admin/owners#enabled
disabled_admin_owners GET /admin/owners/disabled(.:format) admin/owners#disabled
currencies_admin_owner GET /admin/owners/:id/currencies(.:format) admin/owners#currencies
admin_owners GET /admin/owners(.:format) admin/owners#index
admin_owner GET /admin/owners/:id(.:format) admin/owners#show
enabled_admin_counterparties GET /admin/counterparties/enabled(.:format) admin/counterparties#enabled
disabled_admin_counterparties GET /admin/counterparties/disabled(.:format) admin/counterparties#disabled
admin_counterparties GET /admin/counterparties(.:format) admin/counterparties#index
admin_counterparty GET /admin/counterparties/:id(.:format) admin/counterparties#show
enabled_admin_venues GET /admin/venues/enabled(.:format) admin/venues#enabled
disabled_admin_venues GET /admin/venues/disabled(.:format) admin/venues#disabled
admin_venues GET /admin/venues(.:format) admin/venues#index
admin_venue GET /admin/venues/:id(.:format) admin/venues#show
enabled_admin_custody_banks GET /admin/custody_banks/enabled(.:format) admin/custody_banks#enabled
disabled_admin_custody_banks GET /admin/custody_banks/disabled(.:format) admin/custody_banks#disabled
admin_custody_banks GET /admin/custody_banks(.:format) admin/custody_banks#index
admin_custody_bank GET /admin/custody_banks/:id(.:format) admin/custody_banks#show
enabled_admin_client_currencies GET /admin/client_currencies/enabled(.:format) admin/client_currencies#enabled
disabled_admin_client_currencies GET /admin/client_currencies/disabled(.:format) admin/client_currencies#disabled
admin_client_currencies GET /admin/client_currencies(.:format) admin/client_currencies#index
admin_client_currency GET /admin/client_currencies/:id(.:format) admin/client_currencies#show
admin_currencies /admin/currencies(.:format) admin/client_currencies#index
admin_all_currencies /admin/all_currencies(.:format) admin/currencies#index
enabled_admin_groups GET /admin/groups/enabled(.:format) admin/groups#enabled
disabled_admin_groups GET /admin/groups/disabled(.:format) admin/groups#disabled
admin_groups GET /admin/groups(.:format) admin/groups#index
admin_group GET /admin/groups/:id(.:format) admin/groups#show
enabled_admin_groups_accounts GET /admin/groups/accounts/enabled(.:format) admin/groups/accounts#enabled
disabled_admin_groups_accounts GET /admin/groups/accounts/disabled(.:format) admin/groups/accounts#disabled
admin_groups_accounts GET /admin/groups/accounts(.:format) admin/groups/accounts#index
admin_groups_account GET /admin/groups/accounts/:id(.:format) admin/groups/accounts#show
enabled_admin_groups_account_owners GET /admin/groups/account_owners/enabled(.:format) admin/groups/account_owners#enabled
disabled_admin_groups_account_owners GET /admin/groups/account_owners/disabled(.:format) admin/groups/account_owners#disabled
admin_groups_account_owners GET /admin/groups/account_owners(.:format) admin/groups/account_owners#index
admin_groups_account_owner GET /admin/groups/account_owners/:id(.:format) admin/groups/account_owners#show
enabled_admin_groups_users GET /admin/groups/users/enabled(.:format) admin/groups/users#enabled
disabled_admin_groups_users GET /admin/groups/users/disabled(.:format) admin/groups/users#disabled
admin_groups_users GET /admin/groups/users(.:format) admin/groups/users#index
admin_groups_user GET /admin/groups/users/:id(.:format) admin/groups/users#show
enabled_admin_groups_counterparties GET /admin/groups/counterparties/enabled(.:format) admin/groups/counterparties#enabled
disabled_admin_groups_counterparties GET /admin/groups/counterparties/disabled(.:format) admin/groups/counterparties#disabled
admin_groups_counterparties GET /admin/groups/counterparties(.:format) admin/groups/counterparties#index
admin_groups_counterparty GET /admin/groups/counterparties/:id(.:format) admin/groups/counterparties#show
enabled_admin_groups_currencies GET /admin/groups/currencies/enabled(.:format) admin/groups/currencies#enabled
disabled_admin_groups_currencies GET /admin/groups/currencies/disabled(.:format) admin/groups/currencies#disabled
admin_groups_currencies GET /admin/groups/currencies(.:format) admin/groups/currencies#index
admin_groups_currency GET /admin/groups/currencies/:id(.:format) admin/groups/currencies#show
root / trades#index
jasminerice /jasmine Jasminerice::Engine
You need to move this route further down the route list.
admin_group GET /admin/groups/:id(.:format) admin/groups#show
The route list is searched in-order. /admin/groups/users is matching this route with :id equal to users.
render is either in the form
render :json => #user_groups
in which it calls to_json for you and it cannot pass arguments, or you can do this:
format.json { render #user_groups.to_json(:include => [:group_type, :users], :methods => :enabled) }
If you always want to return json no matter what format is, then just get rid of the json: thing:
render #user_groups.to_json(:include => [:group_type, :users], :methods => :enabled)
Please change your routes to this and check
namespace :admin do
namespace :groups do
resources :users, :only => [:index,:show],:collection => {:enabled => :get,:disabled => :get}
end
end
This must be an easy one, but I'm stuck...
So I'm using Rails#3 with Mongoid and want to dynamically build query that would depend upon passed parameters and then execute find().
Something like
def select_posts
query = :all # pseudo-code here
if (params.has_key?(:author))
query += where(:author => params[:author]) # this is pseudo-code again
end
if (params.has_key?(:post_date))
query += where(:create_date => params[:post_date]) # stay with me
end
#post_bodies = []
Post.find(query).each do |post| # last one
#post_bodies << post.body
end
respond_to do |format|
format.html
format.json { render :json => #post_bodies }
end
end
You have a few different options to go with here - depending on how complex your actual application is going to get. Using your example directly - you could end up with something like:
query = Post.all
query = query.where(:author => params[:author]) if params.has_key?(:author)
query = query.where(:create_date => params[:post_date]) if params.has_key?(:post_date)
#post_bodies = query.map{|post| post.body}
Which works because queries (Criteria) in Mongoid are chainable.
Alternatively, if you're going to have lots more fields that you wish to leverage, you could do the following:
query = Post.all
fields = {:author => :author, :post_date => :create_date}
fields.each do |params_field, model_field|
query = query.where(model_field => params[params_field]) if params.has_key?(params_field)
end
#post_bodies = query.map{|post| post.body}
And finally, you can take it one level further and properly nest your form parameters, and name the parameters so that they match with your model, so that your params object looks something like this:
params[:post] = {:author => "John Smith", :create_date => "1/1/1970", :another_field => "Lorem ipsum"}
Then you could just do:
#post_bodies = Post.where(params[:post]).map{|post| post.body}
Of course, with that final example, you'd want to sanitize the input fields - to prevent malicious users from tampering with the behaviour.
I have been struggling with this for a while. As well as some specific help I would be grateful for some pointers how I may fill some of the gaps in my knowledge. BTW I am new to Rails and web development.
I have used DataTables to display a table records and have some code which shows me the id of the row selected by the user. From within my index view I want to use that row id to load the edit view for that data row. My .js code is as follows:
$(document).ready(function() {
/* Init the table */
TableTools.DEFAULTS.aButtons = [];
oTable = $("#highways").dataTable({
sPaginationType: "full_numbers",
bJQueryUI: true,
"bProcessing": true,
"bServerSide": true,
iDisplayLength: 25,
sAjaxSource: $('#highways').data('source'),
"aoColumns": [
null,
null,
null,
null,
null
],
"sDom": 'T<"clear">lfrtip',
"oTableTools": {
"sRowSelect": "single",
"fnRowSelected": function ( node ) {
var oTT = TableTools.fnGetInstance('highways');
var aData = oTT.fnGetSelectedData();
var n = '/highways/' + aData[0][4] + '/edit'
alert(n);
var jqxhr = $.get(n, function() {
alert("success");
})
}
},
});
} );
The development log shows:
Started GET "/highways/8/edit" for 127.0.0.1 at 2012-08-21 07:57:14 +1000
Processing by HighwaysController#edit as /
Parameters: {"id"=>"8"}
[1m[35mHighway Load (0.3ms)[0m SELECT highways.* FROM highways WHERE highways.id >= 8 LIMIT 1
Highway BARKLY HIGHWAY
Rendered highways/_form.html.erb (67.1ms)
Rendered highways/edit.html.erb within layouts/highways (258.5ms)
Completed 200 OK in 276ms (Views: 274.6ms | ActiveRecord: 0.3ms)
I have tried various things in the controller code, and in some cases the log says the edit view has been renedered but it does not show in the browser. Current controller code:
class HighwaysController < ApplicationController
respond_to :html, :json
def index
# #highways = Highway.all
# logger.debug "Highway Count: #{#highways.size}"
respond_to do |format|
format.html
format.json { render json: HighwaysDatatable.new(view_context) }
end
end
def edit
# logger.debug "Edit (render :layout => false) Highway ID #{params[:id]}"
#highway = Highway.find(params[:id])
logger.debug "Highway #{#highway.name}"
# render
respond_to do |format|
format.html
format.json { render json: HighwaysDatatable.edit(view_context) }
end
Is the $.get returning JSON ?
I have also tried a different approach. I have a link_to in the index view:
<div id ="highway_edit" >
<% #n = 11.to_s %>
<%= link_to "Edit 2", edit_highway_path(#n), :remote => true %>
</div>
This hard coded version works but I could not find a way to modify that link from within the javascript code so that it reflected the selected row id, or to call a function which would return the row id into the variable #n.
I realize that there must be some fundamentals I am missing so some suggested starting points for my education would be appreciated. I have read many other related questions but do not have enough knowledge to extract what I need.
PS I see that DataTables has an Editor feature which does pretty much what I want to achieve in the long run, but it is not 'Rails ready'.
Thanks!
EDIT:
In preparing this question I did not properly restore my code to the stage I wanted to discuss. So I have changed the controller code and the subsequent development log. So instead of a template error the problem is that the view is not rendered.
EDIT
I have proceeded with this problem and now have a result. I added a new div (class of 'result') to the top of my index view and changed my js code as follows:
var n = '/highways/' + aData[0][4] + '/edit'
$.get(n, function(data) {
$('.result').html(data);
and the edit view is rendered in that div. The result is ugly as it pushes the table down and doubles up the DataTable headers and footer. But at least it renders. I don't understand why this works when both ways go via the Edit method in the controller. I can now work on the cosmetics, or better still have the edit view appear as a modal overlay.
I would prefer to be able to click (or preferably double-click) a row and the edit view for that row be loaded. I will continue to look to do it that way. In the meantime I have added a link to the view:
<div id="EditLink">
<%= link_to "Edit Highway", :controller => :highways, :action => :edit, :id => 1 %>
</div>
and have the following code in the call back function:
"oTableTools": {
"sRowSelect": "single",
"fnRowSelected": function(node) {
var oTT = TableTools.fnGetInstance('highways');
var aData = oTT.fnGetSelectedData();
$("div#EditLink a").attr('href','/highways/' + aData[0][4] + '/edit')
}
},
which modifies the link based on the id of the selected row. Using this method the user has to know to first select a row and then click the link. If they do not first select a row they will go to the default (id = 1). You have to make sure that such an id exists in the table.